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

Практикум

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

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

    [student@p620 ~]$ sudo systemctl status postgresql ● postgresql.service - Runners PostgreSQL service
    Loaded: loaded (/etc/systemd/system/postgresql.service; enabled; vendor preset: disabled)
    Active: active (running) since Fri 2024-11-08 11:27:25 MSK; 12min ago
    Main PID: 806 (postgres)
    Tasks: 11 (limit: 4652)
    Memory: 63.2M
    CPU: 1.468s
    CGroup: /system.slice/postgresql.service
    ├─ 806 /usr/pangolin-6.2.0/bin/postgres -D /pgdata/06/data
    ├─ 901 "postgres: logger " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""
    ├─ 905 "postgres: checkpointer " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""
    ├─ 906 "postgres: background writer " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""
    ├─ 918 "postgres: walwriter " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""
    ├─ 920 "postgres: autovacuum launcher " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""
    ├─ 921 "postgres: autounite launcher " "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""
    ├─ 922 "postgres: integrity check launcher " "" "" "" "" "" "" "" "" "" "" "" "" "" ""
    └─ 923 "postgres: logical replication launcher " "" "" "" "" "" "" "" "" "" "" "" ""
  2. Если вместо приведенного выше вывода видите следующее:

    [student@p620 ~]$ sudo systemctl status postgresql ○ postgresql.service - Runners PostgreSQL service
    Loaded: loaded (/etc/systemd/system/postgresql.service; enabled; vendor preset: disabled)
    Active: inactive (dead) since Fri 2024-11-08 11:42:07 MSK; 2s ago
    Process: 806 ExecStart=/bin/bash -i -c /usr/pangolin-6.2.0/bin/postgres -D /pgdata/06/data
    (code=exited, status=0/SUCCESS)
    Main PID: 806 (code=exited, status=0/SUCCESS)
    CPU: 1.749s

    то необходимо запустить сервер:

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

    [student@p620 ~]$ ps f -C postgres

    PID TTY
    9675 ?
    9699 ?
    9700 ?
    9701 ?
    STAT TIME COMMAND
    Ss 0:00 /usr/pangolin-6.2.0/bin/postgres -D /pgdata/06/data
    Ss 0:00 \_ postgres: logger
    Ss 0:00 \_ postgres: checkpointer
    Ss 0:00 \_ postgres: background writer
    9703 ?
    9704 ?
    9705 ?
    9706 ?
    9707 ?
    9708 ?
    9709 ?
    Ss 0:00 \_ postgres: idle sessions terminator
    Ss 0:00 \_ postgres: walwriter
    Ss 0:00 \_ postgres: license checker
    Ss 0:00 \_ postgres: autovacuum launcher
    Ss 0:00 \_ postgres: autounite launcher
    Ss 0:00 \_ postgres: integrity check launcher
    Ss 0:00 \_ postgres: logical replication launcher
  4. Откройте в графическом эмуляторе терминала вкладку, или запустите еще один терминал. В новом терминале выполните команды:

[student@p620 ~]$ sudo -iu postgres [postgres@p620 ~]$ psql
psql (15.5)
Type "help" for help.
postgres=#

Первая команда (sudo) запускает оболочку Bash от имени пользователя postgres. Вторая команда запускает клиент psql, в результате чего у вас имеется клиент - серверное соединение. 5. Узнайте PID серверного процесса, обслуживающего вашу сессию в psql, выполнив команду в psql:

postgres=# select pg_backend_pid(); pg_backend_pid
----------------
9787
(1 row)

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

Если в конце команды не введена точка с запятой, а далее нажат Enter, на экране будет видно следующее:

postgres=# select pg_backend_pid() postgres-#

Обратите внимание на символ -# в конце приглашения командной строки. Оно сообщает о том, что ввод команды не завершен и надо либо отказаться от ввода команды, нажав Ctrl+C, либо ввести точку с запятой и Enter:

postgres=# select pg_backend_pid() postgres-# ;
pg_backend_pid
----------------
(1 row)

Этот механизм позволяет вводить длинные команды SQL, разбивая их на отдельные строки. Только в самом конце длинной команды надо ввести ;. 6. Проверьте, что в списке процессов экземпляра появился обслуживающий процесс с выведенным функцией pg_backend_pid() PID:

postgres=# select pg_backend_pid() postgres-# ;
pg_backend_pid
----------------
9787
(1 row)
postgres=# \! ps f -C postgres
PID TTY
9675 ?
9699 ?
9700 ?
9701 ?
9703 ?
9704 ?
9705 ?
9706 ?
9707 ?
9708 ?
9709 ?
9787 ?
STAT TIME COMMAND
Ss 0:00 /usr/pangolin-6.2.0/bin/postgres -D /pgdata/06/data
Ss 0:00 \_ postgres: logger
Ss 0:00 \_ postgres: checkpointer
Ss 0:00 \_ postgres: background writer
Ss 0:00 \_ postgres: idle sessions terminator
Ss 0:00 \_ postgres: walwriter
Ss 0:00 \_ postgres: license checker
Ss 0:00 \_ postgres: autovacuum launcher
Ss 0:00 \_ postgres: autounite launcher
Ss 0:00 \_ postgres: integrity check launcher
Ss 0:00 \_ postgres: logical replication launcher
Ss 0:00 \_ postgres: postgres postgres [local] idle

Запущенный серверный процесс обеспечивает клиент-серверное взаимодействие с psql.

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

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

    postgres=# \c
    You are now connected to database "postgres" as user "postgres". postgres=# select pg_backend_pid();
    pg_backend_pid
    ----------------
    9988
    (1 row)

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

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

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

    У пользователя dbuser1 пароль, соответствующий его имени. Зайдите в сеанс:

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

    Не удалось. Команда \c - подключиться (connect), первое тире после нее - подключиться к той же БД, к которой выполнено подключение сейчас, dbuser1 - от имени этой роли.

  3. Если вход в сеанс не удался, стоит проверить, почему. По сообщению в примере видно строку Peer authentication failed for user "dbuser1". Это сообщение о том, что не прошла аутентификация по методу peer, которая разрешает зайти в сеанс только тем зарегистрированным в ОС пользователям, чье имя пользователя в ОС совпадает с именем пользователя в PostgreSQL. Проверим содержимое конфигурационного файла, отвечающего за аутентификацию:

    postgres=# select * from pg_hba_file_rules();
    line_number | type | database | user_name | address | netmask | auth_method | options |
    -------------+-------+---------------+-----------+-----------+-----------------------------------------+---------------+---------+
    (7 rows)
    89 | local | {all}
    90 | host | {student}
    93 | host | {all}
    95 | host | {all}
    98 | local | {replication} 99 | host | {replication}
    100 | host | {replication}
    | {all} |
    | {student} | | {all} | | {all} | | {all} | | {all} | | {all} |
    |
    IP | 127.0.0.1 | ::1 |
    | 127.0.0.1 | ::1 |
    255.255.255.255
    255.255.255.255 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
    255.255.255.255 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
    | peer | |
    | scram-sha-256 | | | scram-sha-256 | | | scram-sha-256 | | | peer | | | scram-sha-256 | | | scram-sha-256 | |

    Если в выделенной строке вместо слова peer стоит trust, то сеанс должен был запуститься. В данном случае из-за peer требуется чтобы локальный вход в сеанс осуществлял зарегистрированный пользователь ОС, имя которого совпадает с ролью в PostgreSQL. В данном случае dbuser1 в ОС не зарегистрирован.

  4. Попробуем аутентификацию host. В отличие от local, которая настраивает локальные подключения через Unix сокеты, аутентификация host относится только к сетевым подключениям через сетевые интерфейсы:

    postgres=# select * from pg_hba_file_rules();
    line_number | type | database | user_name | address | netmask | auth_method | options |
    -------------+-------+---------------+-----------+-----------+-----------------------------------------+---------------+---------+
    89 | local | {all}
    90 | host | {student}
    93 | host | {all}
    95 | host | {all}
    98 | local | {replication} 99 | host | {replication}
    100 | host | {replication}
    | {all} | | {student} | | {all} | | {all} | | {all} | | {all} | | {all} |
    | IP | 127.0.0.1 | ::1 | | 127.0.0.1 | ::1 |
    255.255.255.255
    255.255.255.255
    ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
    255.255.255.255 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
    | peer | | | scram-sha-256 | | | scram-sha-256 | | | scram-sha-256 | | | peer | | | scram-sha-256 | | | scram-sha-256 | |
    (7 rows)

    При показанных настройках подключение к любой БД от имени любой роли PostgreSQL через localhost будет требовать подтверждения аутентичности пользователя с помощью пароля:

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

    Подключение установлено. Выйдите из сеанса:

    postgres=> \q [postgres@p620 ~]$

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

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

    [postgres@p620 ~]$ 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
    Password for user postgres:
    SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off)
    You are now connected to database "postgres" as user "postgres" on host "localhost" (address "::1") at port "5432".
    postgres=# \conninfo
    You are connected to database "postgres" as user "postgres" on host "localhost" (address "::1") at port "5432".
    SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off)

    Первый раз подключение было локальное через Unix сокет, и оно не было шифрованным. Второй раз - через сетевой интерфейс localhost, команда \connninfo сообщает, что это соединение шифрованное (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384).

Сокеты

  1. Проверьте наличие Unix сокета в каталоге /tmp:

    postgres=# \! ls -al /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

    Команда в клиенте psql \! позволяет выполнить команду ОС без выхода из программы psql. Выполнена команда ls -l, предоставляющая подробную информацию о файлах. Из ее вывода заметно, что есть файл /tmp/.s.PGSQL.5432 - сокет. Для файлов-сокетов команда ls -l перед правами доступа rwxrwxrwx пишет тип файла - s (socket).

  2. Проверьте, какой процесс сейчас работает с этим файлом:

    postgres=# \! lsof /tmp/.s.PGSQL.5432
    COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
    postgres 9675 postgres 8u unix 0x00000000ccb46eea 0t0 44241 /tmp/.s.PGSQL.5432 type=STREAM
  3. Узнайте, что это за процесс:

    postgres=# \! ps -fp 9675
    UID PID PPID C STIME TTY TIME CMD
    postgres 9675 1 0 11:44 ? 00:00:02 /usr/pangolin-6.2.0/bin/postgres -D /pgdata/06/data

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

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

    postgres=# \dconfig listen*|port|unix*dir* List of configuration parameters
    Parameter | Value
    -------------------------+-------
    listen_addresses | *
    port | 5432
    unix_socket_directories | /tmp
    (3 rows)
  2. Проверьте, действительно ли прослушиваются данные порты:

    postgres=# \! ss -ln | grep 5432
    u_str LISTEN 0 290 /tmp/.s.PGSQL.5432 44241 * 0
    tcp LISTEN 0 290 0.0.0.0:5432 0.0.0.0:*
    tcp LISTEN 0 290 [::]:5432 [::]:*

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

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

    postgres=# \! cat $PGDATA/postmaster.pid 9675
    /pgdata/06/data
    1731055479
    5432 /tmp *
    786435 51
    ready

    Переменная PGDATA указывает имя каталога данных кластера. Доллар перед именем переменной извлекает значение из нее.

  2. Извлеките из файла postmaster.pid утилитой head первую строку и подставьте ее в утилиту ps для получения отчета о статусе головного процесса экземпляра:

    postgres=# \! ps -fp $(head -1 $PGDATA/postmaster.pid)
    UID PID PPID C STIME TTY TIME CMD
    postgres 9675 1 0 11:44 ? 00:00:02 /usr/pangolin-6.2.0/bin/postgres -D /pgdata/06/data

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

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

    postgres=# \q

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

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

    [postgres@p620 ~]$ 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 template1 - localhost
    Password for user postgres:
    SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off)
    You are now connected to database "template1" as user "postgres" on host "localhost" (address "::1") at port "5432".
    template1=# select user, current_catalog, inet_server_port(), inet_server_addr();
    user | current_catalog | inet_server_port | inet_server_addr
    ----------+-----------------+------------------+------------------
    postgres | template1 | 5432 | ::1
    (1 row)

    Обратите внимание, что подключение произведено через localhost по протоколу IPv6 - адрес ::1/128.

  3. Подключитесь от имени пользователя dbuser1 и проверьте те же параметры:

    template1=# \c template1 dbuser1 localhost
    Password for user dbuser1:
    SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off) You are now connected to database "template1" as user "dbuser1".
    template1=> select user, current_catalog, inet_server_port(), inet_server_addr();
    user | current_catalog | inet_server_port | inet_server_addr
    ---------+-----------------+------------------+------------------
    dbuser1 | template1 | 5432 | ::1
    (1 row)
    template1=> \q

Библиотека libpq

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

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

    [postgres@p620 ~]$ ldd `which psql` | grep libpq
    libpq.so.5 => /usr/pangolin/lib/libpq.so.5 (0x00007f2051065000)