Перейти к основному содержимому

Клиент-серверное взаимодействие

Предусловие: пройдены практические задания предыдущего модуля: «Ручная установка Pangolin» и «Запуск systemd для Pangolin».

В задании «Запуск systemd для Pangolin» мы уже настроили сервис postgresql, который управляет работой СУБД Pangolin.

  1. Проверьте, запущен ли сервис:

    [student@ServerName ~]$ sudo systemctl status postgresql
    ● postgresql.service - Runners PostgreSQL service
    Loaded: loaded (/etc/systemd/system/postgresql.service; disabled; vendor preset: disabled)
    Active: active (running) since Wed 2025-05-07 09:50:27 MSK; 8s ago
    Process: 11933 ExecStartPre=/bin/mkdir -p /var/run/postgresql (code=exited, status=0/SUCCESS)
    Process: 11934 ExecStartPre=/bin/chown -R postgres:postgres /var/run/postgresql (code=exited, status=0/SUCCESS)
    Main PID: 11935 (postgres)
    Tasks: 10 (limit: 2362)
    Memory: 28.6M
    CGroup: /system.slice/postgresql.service
    ├─11935 /usr/pangolin-{major.minor}/bin/postgres -D /pgdata/06/data
    ├─11939 postgres: checkpointer
    ├─11940 postgres: background writer
    ├─11942 postgres: idle sessions terminator
    ├─11943 postgres: walwriter
    ├─11944 postgres: autovacuum launcher
    ├─11945 postgres: autounite launcher
    ├─11946 postgres: integrity check launcher
    ├─11947 postgres: license checker
    └─11948 postgres: logical replication launcher
  2. Если сервис неактивен (вывод содержит Active: inactive (dead)), его необходимо запустить:

    [student@ServerName ~]$ sudo systemctl start postgresql
  3. Получите список процессов экземпляра:

    [student@ServerName ~]$ ps f -C postgres
    PID TTY STAT TIME COMMAND
    11935 ? Ss 0:00 /usr/pangolin-{major.minor}/bin/postgres -D /pgdata/06/data
    11939 ? Ss 0:00 \_ postgres: checkpointer
    11940 ? Ss 0:00 \_ postgres: background writer
    11942 ? Ss 0:00 \_ postgres: idle sessions terminator
    11943 ? Ss 0:00 \_ postgres: walwriter
    11944 ? Ss 0:00 \_ postgres: autovacuum launcher
    11945 ? Ss 0:00 \_ postgres: autounite launcher
    11946 ? Ss 0:00 \_ postgres: integrity check launcher
    11947 ? Ss 0:00 \_ postgres: license checker
    11948 ? Ss 0:00 \_ postgres: logical replication launcher
    Разбор команды:

    • ps – утилита для просмотра информации о процессе;
    • f – отображает процессы в виде дерева (родитель-потомки);
    • -C postgres – выбирает процессы с именем postgres.

    Подробнее об опциях ps можно узнать в man ps.

    Головной процесс (PID 11935) запускает все остальные. Каждый из дочерних процессов выполняет свою функцию – запись журналов, обслуживание кешей, проверку целостности и другие.

  4. Для подключения к серверу используется клиент psql. Откройте новый терминал (или вкладку) и выполните:

    [student@ServerName ~]$ sudo su - postgres
    [postgres@ServerName ~]$ psql
    psql (15.5)
    Type "help" for help.

    postgres=#

    Первая команда (sudo) запускает оболочку Bash от имени пользователя postgres. Вторая команда запускает клиент psql, в результате чего у вас имеется клиент-серверное соединение.

  5. Каждое клиентское соединение обслуживается отдельным серверным процессом. Узнайте его PID с помощью функции pg_backend_pid():

    postgres=# SELECT pg_backend_pid();
    pg_backend_pid
    ----------------
    12105
    (1 row)

    Обратите внимание на точку с запятой в конце команды. Она означает, что ввод команды SQL закончен.

    А если ее не поставить?

    Если точку с запятой не поставить, psql будет ожидать продолжения ввода, что отражается в приглашении -#:

    postgres=# SELECT pg_backend_pid()
    postgres-#

    Чтобы завершить команду, нужно ввести ; и нажать Enter, либо отменить ввод комбинацией Ctrl+C.

    Этот механизм позволяет вводить длинные команды SQL, разбивая их на отдельные строки. Только в самом конце длинной команды надо ввести ;.

  6. Проверьте, что в списке процессов экземпляра появился обслуживающий процесс с полученным PID (в примере это процесс 12105):

    postgres=# \! ps f -C postgres
    PID TTY STAT TIME COMMAND
    11935 ? Ss 0:00 /usr/pangolin-{major.minor}/bin/postgres -D /pgdata/06/data
    11939 ? Ss 0:00 \_ postgres: checkpointer
    11940 ? Ss 0:00 \_ postgres: background writer
    11942 ? Ss 0:00 \_ postgres: idle sessions terminator
    11943 ? Ss 0:00 \_ postgres: walwriter
    11944 ? Ss 0:00 \_ postgres: autovacuum launcher
    11945 ? Ss 0:00 \_ postgres: autounite launcher
    11946 ? Ss 0:00 \_ postgres: integrity check launcher
    11947 ? Ss 0:00 \_ postgres: license checker
    11948 ? Ss 0:00 \_ postgres: logical replication launcher
    12105 ? Ss 0:00 \_ postgres: postgres postgres [local] idle

    Метакоманда \! позволяет выполнить команду ОС без выхода из клиента psql. Запущенный серверный процесс обеспечивает клиент-серверное взаимодействие с psql.

Этапы взаимодействия клиента и сервера​

  1. Перезапустите соединение, выполнив команду psql \с и проверьте, изменился ли PID серверного процесса:

    postgres=# \c
    You are now connected to database "postgres" as user "postgres".
    postgres=# SELECT pg_backend_pid();
    pg_backend_pid
    ----------------
    12161
    (1 row)
    postgres=# \! ps f -C postgres
    PID TTY STAT TIME COMMAND
    11935 ? Ss 0:00 /usr/pangolin-{major.minor}/bin/postgres -D /pgdata/06/data
    11939 ? Ss 0:00 \_ postgres: checkpointer
    11940 ? Ss 0:00 \_ postgres: background writer
    11942 ? Ss 0:00 \_ postgres: idle sessions terminator
    11943 ? Ss 0:00 \_ postgres: walwriter
    11944 ? Ss 0:00 \_ postgres: autovacuum launcher
    11945 ? Ss 0:00 \_ postgres: autounite launcher
    11946 ? Ss 0:00 \_ postgres: integrity check launcher
    11947 ? Ss 0:00 \_ postgres: license checker
    11948 ? Ss 0:00 \_ postgres: logical replication launcher
    12161 ? Ss 0:00 \_ postgres: postgres postgres [local] idle

    Старый серверный процесс (12105) завершен, вместо него запущен новый (12161). Все, что сохранялось в локальной памяти серверного процесса, сброшено. Память клиента psql осталась, так как клиент не рестартовал.

  2. Зарегистрируйте в Pangolin новую роль с паролем. Проверьте, пройдет ли успешно процесс аутентификации при входе в сеанс нового пользователя:

    postgres=# CREATE USER dbuser1 PASSWORD 'dbuser1';
    CREATE ROLE
    postgres=# \du dbuser1
    List of roles
    Role name | Attributes | Member of
    -----------+------------+-----------
    dbuser1 | | {}

    Метакоманда \du выводит список ролей базы данных. Подробнее об этом рассказывается в курсе DBA1 в главе «Авторизация и аутентификация».

    Подключитесь в сеанс от имени dbuser1 через Unix-сокет:

    postgres=# \c - dbuser1
    You are now connected to database "postgres" as user "dbuser1".
  3. Подключитесь в сеанс от имени dbuser1 через сеть:

    postgres=# \c - dbuser1 localhost
    You are now connected to database "postgres" as user "dbuser1" on host "localhost" (address "::1") at port "5432".
  4. Подключение установлено. Выйдите из сеанса:

    postgres=> \q

Параметры соединения​

  1. Войдите в сеанс:

    [postgres@ServerName ~]$ psql
    psql (15.5)
    Type "help" for help.
    postgres=#
  2. Проверьте, как было установлено соединение:

    postgres=# \conninfo
    You are connected to database "postgres" as user "postgres" via socket in "/tmp" at port "5432".
  3. Переподключитесь через localhost:

    postgres=# \c - - localhost
    You are now connected to database "postgres" as user "postgres" on host "localhost" (address "127.0.0.1") at port "5432".
    postgres=# \conninfo
    You are connected to database "postgres" as user "postgres" on host "localhost" (address "127.0.0.1") at port "5432".
    SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off)

    Если соединение будет засекреченным, как при сетевом подключении, то команда \connninfo сообщит об этом – SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off).

Сокеты​

  1. Вернитесь к подключению через Unix-сокет:

    postgres=# \c - - /tmp
    You are now connected to database "postgres" as user "postgres" via socket in "/tmp" at port "5432".
  2. Проверьте наличие файла Unix-сокета в каталоге /tmp:

    postgres=# \! ls -la /tmp/.*5432*
    srwxrwxrwx 1 postgres postgres 0 Nov 8 11:44 /tmp/.s.PGSQL.5432
    -rw------- 1 postgres postgres 42 Nov 8 11:44 /tmp/.s.PGSQL.5432.lock

    Выполнена команда ls -l, предоставляющая подробную информацию о файлах, опция -a показывает скрытые файлы и каталоги (начинающиеся с точки).

    Из ее вывода заметно, что есть файл /tmp/.s.PGSQL.5432 — сокет. Для файлов-сокетов команда ls -l перед правами доступа rwxrwxrwx пишет тип файла — s (socket). Файл /tmp/.s.PGSQL.5432.lock – это блокировка, предотвращающая одновременный запуск нескольких экземпляров.

  3. Проверьте, какие процессы сейчас используют этот сокет:

    postgres=# \! lsof /tmp/.s.PGSQL.5432
    COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
    postgres 11935 postgres 6u unix 0x0000000000000000 0t0 155748 /tmp/.s.PGSQL.5432 type=STREAM
    postgres 12943 postgres 7u unix 0x0000000000000000 0t0 159730 /tmp/.s.PGSQL.5432 type=STREAM
  4. Узнайте, что это за процессы:

    postgres=# \! ps -fp 11935
    UID PID PPID C STIME TTY TIME CMD
    postgres 11935 1 0 09:50 ? 00:00:00 /usr/pangolin-{major.minor}/bin/postgres -D /pgdata/06/data
    postgres=# \! ps -fp 12943
    UID PID PPID C STIME TTY TIME CMD
    postgres 12943 11935 0 10:44 ? 00:00:00 postgres: postgres postgres [local] idle

    Первый процесс (11935) – головной процесс экземпляра, второй (12943) – серверный процесс, обслуживающий текущую сессию.

Настройки сервера для сокетов​

  1. Проверьте, как настроен экземпляр: какие сетевые интерфейсы прослушиваются, номер порта TCP и расположение сокета в файловой системе:

    postgres=# \dconfig listen*|port|unix*dir*
    List of configuration parameters
    Parameter | Value
    -------------------------+-------
    listen_addresses | *
    port | 5432
    unix_socket_directories | /tmp
    (3 rows)

    Где:

    • \dconfig – метакоманда для просмотра параметров конфигурации сервера и их значений;
    • шаблон listen*|port|unix*dir* выбирает параметры, содержащие указанные строки.
  2. Проверьте, действительно ли прослушиваются данные порты:

    postgres=# \! ss -ln | grep 5432
    u_str LISTEN 0 294 /tmp/.s.PGSQL.5432 155748 * 0
    tcp LISTEN 0 294 0.0.0.0:5432 0.0.0.0:*

Информация о сервере​

  1. Исследуйте содержимое файла postmaster.pid:

    postgres=# \! cat $PGDATA/postmaster.pid
    11935
    /pgdata/06/data
    1746600627
    5432
    /tmp
    *
    652803 7
    ready

    Обратите внимание на PID (11935). Вы его уже встречали ранее. Сделайте выводы.

  2. Получите отчет о статусе головного процесса экземпляра:

    postgres=# \! ps -fp $(head -1 $PGDATA/postmaster.pid)
    UID PID PPID C STIME TTY TIME CMD
    postgres 11935 1 0 09:50 ? 00:00:00 /usr/pangolin-{major.minor}/bin/postgres -D /pgdata/06/data

    Конструкция $() — командная подстановка, вместо нее подставляется результат выполненной команды, в данном случае head -1 (первая строка файла).

  3. Выйдите из сеанса:

    postgres=# \q

Получение информации о сеансе​

  1. Зайдите в сеанс из-под сессии postgres в ОС и получите информацию о пользователе в сеансе СУБД Pangolin – текущую БД, сетевой порт TCP и адрес источника соединения:

    [postgres@ServerName ~]$ psql
    psql (15.5)
    Type "help" for help.
    postgres=# SELECT user, current_catalog, inet_server_port(), inet_server_addr();
    user | current_catalog | inet_server_port | inet_server_addr
    ----------+-----------------+------------------+------------------
    postgres | postgres | |
    (1 row)

    Так как подключение в данной сессии произведено через сокет, функции inet_server_port() и inet_server_addr() возвращают NULL.

  2. Подключитесь через localhost и проверьте те же параметры:

    postgres=# \c - - localhost
    You are now connected to database "postgres" as user "postgres" on host "localhost" (address "127.0.0.1") at port "5432".
    postgres=# SELECT user, current_catalog, inet_server_port(), inet_server_addr();
    user | current_catalog | inet_server_port | inet_server_addr
    ----------+-----------------+------------------+------------------
    postgres | postgres | 5432 | 127.0.0.1
    (1 row)
  3. Подключитесь от имени пользователя dbuser1 и проверьте те же параметры:

    postgres=# \c postgres dbuser1 localhost
    You are now connected to database "postgres" as user "dbuser1".
    postgres=> SELECT user, current_catalog, inet_server_port(), inet_server_addr();
    user | current_catalog | inet_server_port | inet_server_addr
    ---------+-----------------+------------------+------------------
    dbuser1 | postgres | 5432 | 127.0.0.1
    (1 row)
  4. Выйдите из сеанса:

    postgres=> \q

Библиотека libpq​

Клиент psql использует библиотеку libpq для взаимодействия с сервером. Убедимся в этом:

  1. Получите путь к исполняемому файлу psql:

    [postgres@ServerName ~]$ which psql
    /usr/bin/psql
  2. Проверьте, загружается ли библиотека libpq при старте этой программы:

    [postgres@ServerName ~]$ ldd `which psql` | grep libpq
    libpq.so.5 => /usr/pangolin/lib/libpq.so.5 (0x00007fcff7ade000)
  3. В завершение работы выйдите из сеанса postgres:

    [postgres@ServerName ~]$ exit
    logout

На этом работу с клиентским подключением в Pangolin можно считать завершенной.

Самопроверка​

Вопрос 1

В сеансе psql выполнена команда:

postgres=# \! ps f -C postgres
PID TTY      STAT   TIME COMMAND
986 ?        Ss     0:03 /usr/pangolin-\{pangolin-version\}/bin/postgres -D /pgdata/06/data
1085 ?        Ss     0:00  \_ postgres: logger
1099 ?        Ss     0:00  \_ postgres: checkpointer
1100 ?        Ss     0:00  \_ postgres: background writer
1101 ?        Ss     0:00  \_ postgres: idle sessions terminator
1247 ?        Ss     0:00  \_ postgres: walwriter
1248 ?        Ss     0:00  \_ postgres: license checker
1249 ?        Ss     0:00  \_ postgres: autovacuum launcher
1250 ?        Ss     0:00  \_ postgres: autounite launcher
1251 ?        Ss     0:00  \_ postgres: integrity check launcher
1252 ?        Ss     0:00  \_ postgres: logical replication launcher
30003 ?        Ss     0:00  \_ postgres: postgres postgres [local] idle

Какое число выдаст запрос SELECT pg_backend_pid();, выполненный в том же сеансе psql?

Вопрос 2

В сеансе psql выполнены следующие команды:

postgres=# SHOW enabled_extra_auth_methods;
enabled_extra_auth_methods
----------------------------
scram-sha-256, peer
(1 row)

postgres=# CREATE ROLE test_user PASSWORD 'password';
CREATE ROLE

postgres=# SELECT * FROM pg_hba_file_rules();
line_number | type  |   database    | user_name  |  address  |                 netmask                 |  auth_method  | options | error
-------------+-------+---------------+------------+-----------+-----------------------------------------+---------------+---------+-------
95 | local | {all}         | {all}      |           |                                         | peer          |         |
97 | host  | {all}         | {all}      | 127.0.0.1 | 255.255.255.255                         | scram-sha-256 |         |
99 | host  | {all}         | {all}      | ::1       | ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff | scram-sha-256 |         |
102 | local | {replication} | {all}      |           |                                         | peer          |         |
103 | host  | {replication} | {all}      | 127.0.0.1 | 255.255.255.255                         | scram-sha-256 |         |
104 | host  | {replication} | {all}      | ::1       | ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff | scram-sha-256 |         |

postgres=# \c - test_user
connection to server on socket "/tmp/.s.PGSQL.5432" failed: FATAL: Peer authentication failed for user "test_user"
Previous connection kept

Каким образом можно обеспечить подключение роли test_user к текущей базе данных в данном сеансе psql? Рассмотрите следующие варианты:

  • Вариант 1. Путем последовательного выполнения следующих действий:

    • в файле pg_hba.conf удалить 95-ю строку
    • в psql выполнить запрос SELECT pg_reload_conf();
    • в psql выполнить команду \c - test_user и ввести пароль пользователя
  • Вариант 2. Путем последовательного выполнения следующих действий:

    • в файле pg_hba.conf в 95-й строке изменить значение поля auth_method на scram-sha-256
    • в psql выполнить запрос SELECT pg_reload_conf();
    • в psql выполнить команду \c - test_user и ввести пароль пользователя
  • Вариант 3. Выполнить в psql команду \c - test_user localhost и ввести пароль пользователя

Выберите верные варианты.

Вопрос 3

В shell выполнена команда:

ps f -C postgres
PID TTY      STAT   TIME COMMAND
986 ?        Ss     0:03 /usr/pangolin-\{pangolin-version\}/bin/postgres -D /pgdata/06/data
1085 ?        Ss     0:00  \_ postgres: logger
1099 ?        Ss     0:00  \_ postgres: checkpointer
1100 ?        Ss     0:00  \_ postgres: background writer
1101 ?        Ss     0:00  \_ postgres: idle sessions terminator
1247 ?        Ss     0:00  \_ postgres: walwriter
1248 ?        Ss     0:00  \_ postgres: license checker
1249 ?        Ss     0:00  \_ postgres: autovacuum launcher
1250 ?        Ss     0:00  \_ postgres: autounite launcher
1251 ?        Ss     0:00  \_ postgres: integrity check launcher
1252 ?        Ss     0:00  \_ postgres: logical replication launcher
30003 ?        Ss     0:00  \_ postgres: postgres postgres [local] idle

Какое число выдаст команда shell sudo head -1 $PGDATA/postmaster.pid?

Вопрос 4

В сеансе psql выполнен следующий запрос:

postgres=# SELECT inet_server_addr();
inet_server_addr
-------------
::1

С использованием какого сетевого протокола выполнено подключение в данном сеансе?