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

Уровень 3.0

Предусловия:

  • Изучена лекция 4 «Протокол репликации и архив WAL»

Настройка потокового и непрерывного архивирований​

Подготовка виртуальной машины Host1​

  1. Подключитесь к виртуальной машине посредством webssh, указав ip-адрес Host1 .

  2. В терминале подключитесь в psql к базе данных postgres от имени пользователя postgres:

    [student@ServerName ~]$ psql -U postgres
    psql (15.5)
    Type "help" for help.
  3. Создайте роль replicator:

    postgres=# CREATE ROLE replicator WITH LOGIN REPLICATION PASSWORD 'replicator';
    CREATE ROLE

    Указанная роль будет использоваться для подключения по протоколу репликации, поэтому требуется наличие атрибута REPLICATION.

  4. Создайте базу данных archive_db и подключитесь к ней:

    postgres=# CREATE DATABASE archive_db;
    CREATE DATABASE
    postgres=# \c archive_db
    You are now connected to database "archive_db" as user "postgres".

Подготовка виртуальной машины Host2​

  1. Подключитесь к виртуальной машине посредством webssh, указав ip-адрес Host2.

  2. В домашнем каталоге пользователя student создайте каталог archive и перейдите в него:

    [student@ServerName ~]$ mkdir archive && cd archive

Настройка подключения по протоколу репликации​

  1. В сеансе psql на Host1 проверьте значения параметров wal_level, max_wal_senders и max_replication_slots:

    archive_db=# SELECT name, setting FROM pg_settings WHERE name IN ('wal_level', 'max_wal_senders', 'max_replication_slots');
    name | setting
    -----------------------+---------
    max_replication_slots | 10
    max_wal_senders | 10
    wal_level | replica
    (3 rows)

    Вспомним, что для возможности подключения по протоколу репликации уровень журнала (wal_level) должен быть не менее replica.

    Также должно быть достаточным допустимое количество процессов wal sender (max_wal_senders), и в случае использования слота репликации — значение параметра max_replication_slots.

    Значения по умолчанию указанных параметров позволяют использовать протокол репликации в рамках лабораторной работы.

  2. В сеансе psql на Host1 проверьте настройки в файле pg_hba.conf:

    archive_db=# SELECT line_number, type, database, user_name, address, netmask, auth_method FROM pg_hba_file_rules;
    line_number | type | database | user_name | address | netmask | auth_method
    -------------+-------+---------------+-----------+---------------+-----------------------------------------+---------------
    89 | local | {all} | {all} | | | trust
    91 | host | {all} | {all} | 172.29.53.165 | 255.255.255.255 | trust
    92 | host | {all} | {all} | 0.0.0.0 | 0.0.0.0 | scram-sha-256
    93 | host | {all} | {all} | 127.0.0.1 | 255.255.255.255 | trust
    95 | host | {all} | {all} | ::1 | ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff | trust
    98 | local | {replication} | {all} | | | trust
    99 | host | {replication} | {all} | 127.0.0.1 | 255.255.255.255 | trust
    100 | host | {replication} | {all} | ::1 | ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff | trust
    (8 rows)

    Текущие настройки pg_hba.conf не позволяют подключаться по протоколу репликации через сетевой интерфейс. Исправим это.

  3. В сеансе psql на Host1 добавьте в файл pg_hba.conf разрешение для доступа через сетевой интерфейс по протоколу репликации:

    archive_db=# \! sudo sed -i '99i\host replication all 0.0.0.0/0 scram-sha-256' /pgdata/\{pangolin_version\}/data/pg_hba.conf

    В этом случае перед 99-й строкой файла pg_hba.conf была добавлена строка с разрешением доступа через сетевой интерфейс с аутентификацией по паролю.

  4. В сеансе psql на Host1 проверьте корректность внесенных в pg_hba.conf изменений и перечитайте конфигурацию:

    archive_db=# SELECT line_number, type, database, user_name, address, netmask, auth_method FROM pg_hba_file_rules;
    line_number | type | database | user_name | address | netmask | auth_method
    -------------+-------+---------------+-----------+---------------+-----------------------------------------+---------------
    89 | local | {all} | {all} | | | trust
    91 | host | {all} | {all} | 172.29.53.165 | 255.255.255.255 | trust
    92 | host | {all} | {all} | 0.0.0.0 | 0.0.0.0 | scram-sha-256
    93 | host | {all} | {all} | 127.0.0.1 | 255.255.255.255 | trust
    95 | host | {all} | {all} | ::1 | ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff | trust
    98 | local | {replication} | {all} | | | trust
    99 | host | {replication} | {all} | 0.0.0.0 | 0.0.0.0 | scram-sha-256
    100 | host | {replication} | {all} | 127.0.0.1 | 255.255.255.255 | trust
    101 | host | {replication} | {all} | ::1 | ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff | trust
    (9 rows)
    archive_db=# SELECT pg_reload_conf();
    pg_reload_conf
    ----------------
    t
    (1 row)

    Необходимое разрешение успешно добавлено. Для применения новых настроек файлы конфигурации были перечитаны функцией pg_reload_conf.

  5. В терминале на Host2 подключитесь в psql к кластеру, развернутому на Host1, по протоколу репликации. При этом используйте ip-адрес, соответствующий вашей виртуальной машине Host1:

    student@ServerName archive]$ psql "host={replica-IP} user=replicator replication=true"
    Password for user replicator:
    psql (15.5)
    Type "help" for help.

    Вспомним, что psql поддерживает работу по протоколу репликации.

    Для этого в строке подключения было указано replication=true.

  6. В сеансе psql на Host2 выполните одну из команд протокола репликации:

    replicator=> IDENTIFY_SYSTEM;
    systemid | timeline | xlogpos | dbname
    ---------------------+----------+-----------+--------
    7558839795421325717 | 1 | 0/1DC7D78 |
    (1 row)

    Команда IDENTIFY_SYSTEM запрашивает идентификационные данные экземпляра сервера, в том числе идентификатор кластера баз данных (systemid) и текущую позицию записи в журнале WAL (xlogpos), с которой может начаться передача записей по протоколу репликации.

    Поле timeline содержит идентификатор текущей линии времени. Он используется при физическом резервном копировании. Его назначение станет понятным в следующей лекции.

    Поле dbname используется при логической репликации для указания имени базы данных.

    Успешное выполнение команды IDENTIFY_SYSTEM подтверждает подключение по протоколу репликации.

    В протоколе предусмотрен еще ряд команд, среди которых можно выделить команду создания слота репликации (CREATE_REPLICATION_SLOT) и команду запуска потоковой передачи записей WAL (START_REPLICATION).

    Однако напрямую мы их использовать не будем. Вместо этого доверимся утилите pg_receivewal, которая на основе протокола репликации обеспечивает архивирование записей WAL.

    Но для начала сверим полученное значение xlogpos с результатом функции pg_current_wal_lsn, показывающей текущую позицию вставки журнала.

  7. В сеансе psql на Host1 проверьте текущую позицию записи журнала WAL:

    archive_db=# SELECT pg_current_wal_lsn();
    pg_current_wal_lsn
    --------------------
    0/1DC7D78
    (1 row)

    Как и ожидалось, позиции записей совпадают.

  8. Выйдите из psql на Host2:

    replicator=> \q

Потоковое архивирование​

  1. В терминале на Host2 создайте слот репликации с использованием утилиты pg_receivewal. При этом используйте ip-адрес, соответствующий вашей виртуальной машине Host1, а также введите пароль роли replicator ("replicator"):

    [student@ServerName archive]$ pg_receivewal --create-slot --slot=archive_slot -U replicator -h 172.29.53.165
    Password:

    Утилита pg_receivewal позволяет создавать слоты репликации. Для этого были указаны ключ --create-slot и имя слота в ключе --slot.

  2. В сеансе psql на Host1 проверьте наличие созданного слота:

    archive_db=# SELECT slot_name, slot_type, active, restart_lsn FROM pg_replication_slots;
    slot_name | slot_type | active | restart_lsn
    --------------+-----------+--------+-------------
    archive_slot | physical | f |
    (1 row)

    Созданный слот отображается в представлении pg_replication_slots. Однако он еще не использовался, поэтому поле restart_lsn (LSN старейшей записи сегмента, который еще может быть нужен пользователям слота) пустое.

    Значение поля active говорит о том, что слот в текущий момент никем не используется.

  3. В сеансе psql на Host1 проверьте, какой сегмент WAL используется в текущий момент:

    archive_db=# SELECT pg_walfile_name(pg_current_wal_lsn());
    pg_walfile_name
    --------------------------
    000000010000000000000001
    (1 row)

    Пока в журнале WAL всего один сегмент, который используется для сохранения новых записей.

  4. В терминале на Host2 с использованием утилиты pg_receivewal запустите потоковое архивирование. При этом используйте ip-адрес, соответствующий вашей виртуальной машине Host1:

    [student@ServerName archive]$ pg_receivewal -D ./ --slot=archive_slot -d "host={IP-Address} user=replicator password=replicator" &
    [1] 18853

    Теперь было запущено непосредственно потоковое получение записей WAL.

    Это было сделано в фоновом режиме (в конце команды &). Пароль при этом был указан непосредственно в строке подключения.

    Получение записей выполняется посредством созданного слота --slot=archive_slot.

    Записи сохраняются в каталоге archive (-D ./) домашнего каталога пользователя student.

  5. В терминале на Host2 проверьте содержимое текущего каталога:

    [student@ServerName archive]$ ls -1
    000000010000000000000001.partial

    В каталоге archive сразу был создан файл-сегмент. Расширение partial означает, что он еще не заполнен полностью.

  6. В сеансе psql на Host1 создайте простую таблицу и наполните ее данными:

    archive_db=# CREATE TABLE some_table AS SELECT 'Потоковое архивирование!' FROM generate_series(1, 100000);
    SELECT 100000

    Вспомним, что операции массовой обработки данных попадают в журнал при его уровне не менее replica.

  7. В сеансе psql на Host1 проверьте, какой сегмент WAL используется в текущий момент:

    archive_db=# SELECT pg_walfile_name(pg_current_wal_lsn());
    pg_walfile_name
    --------------------------
    000000010000000000000002
    (1 row)

    В этом случае первый сегмент был полностью заполнен, и было осуществлено переключение на следующий сегмент.

  8. В терминале на Host2 проверьте содержимое текущего каталога:

    [student@ServerName archive]$ ls -1
    000000010000000000000001
    000000010000000000000002.partial

    Новые записи сразу попали в архив. Первый сегмент в нем также полностью заполнен.

  9. В сеансе psql на Host1 проверьте состояние слота репликации:

    archive_db=# SELECT slot_name, slot_type, active, restart_lsn FROM pg_replication_slots;
    slot_name | slot_type | active | restart_lsn
    --------------+-----------+--------+-------------
    archive_slot | physical | t | 0/2000000
    (1 row)

    Слот репликации теперь активен и хранит LSN первой записи (restart_lsn) сегмента, начиная с которого контрольная точка не будет удалять накопленные сегменты.

    Тут стоит уточнить, что контрольная точка все же может удалять еще необходимые слотам сегменты WAL.

    Право удаления контрольной точкой сегментов WAL, еще необходимых слотам репликации, возникает в случае превышения их общим размером значения параметра max_slot_wal_keep_size. По умолчанию указанный параметр имеет значение -1, что означает отсутствие ограничения на максимальный размер сегментов WAL, необходимых для контрольных точек.

  10. В терминале на Host2 завершите процесс pg_receivewal.

    При этом используйте pid процесса, полученный при его запуске в фоне в п. 4:

    [student@ServerName archive]$ kill 18853
    [1]+ Terminated pg_receivewal -D ./ --slot=archive_slot -d "host={replica-IP} user=replicator password=replicator"
  11. В сеансе psql на Host1 проверьте состояние слота репликации:

    archive_db=# SELECT slot_name, slot_type, active, restart_lsn FROM pg_replication_slots;
    archive_db=# SELECT slot_name, slot_type, active, restart_lsn FROM pg_replication_slots;
    slot_name | slot_type | active | restart_lsn
    --------------+-----------+--------+-------------
    archive_slot | physical | f | 0/2000000
    (1 row)

    Теперь слот неактивен. При этом restart_lsn не пустой.

    Это означает, что все сегменты начиная с restart_lsn не будут удаляться, пока не пройдут через слот, который никем не используется.

    Как можно догадаться, это плохая ситуация: сегменты будут бесконечно накапливаться.

    Как раз для выявления таких слотов (с целью их дальнейшего удаления) и предназначено представление pg_replication_slots.

  12. В сеансе psql на Host1 удалите слот репликации:

    archive_db=# SELECT pg_drop_replication_slot('archive_slot');
    pg_drop_replication_slot
    --------------------------

    (1 row)
    archive_db=# SELECT slot_name, slot_type, active, restart_lsn FROM pg_replication_slots;
    slot_name | slot_type | active | restart_lsn
    -----------+-----------+--------+-------------
    (0 rows)

    Теперь процессу контрольной точки ничто не препятствует удалить ненужные сегменты WAL.

Непрерывное архивирование​

В этом разделе все команды выполняются на виртуальной машине Host1.

  1. Проверьте, включен ли режим непрерывного архивирования:

    archive_db=# SHOW archive_mode;
    archive_mode
    --------------
    off
    (1 row)

    Вспомним, что непрерывное архивирование осуществляется самим экземпляром сервера путем выполнения команды оболочки.

    По умолчанию оно выключено.

  2. Включите непрерывное архивирование и укажите команду оболочки для копирования сегментов WAL:

    archive_db=# ALTER SYSTEM SET archive_mode = on;
    ALTER SYSTEM
    archive_db=# ALTER SYSTEM SET archive_command = 'test ! -f /home/postgres/archive/%f && cp %p /home/postgres/archive/%f';
    ALTER SYSTEM

    Для указания пути копируемого файла сегмента относительно каталога данных в команде используется подстановка %p, для указания только имени файла — %f.

    В этом случае сначала проверяется наличие файла с названием копируемого сегмента, и только в случае его отсутствия выполняется копирование сегмента.

    Проверка наличия архивного файла перед копированием сегмента с тем же именем — это распространенная мера сохранения целостности архива в случае ошибки администратора.

    Она защищает от перезаписи архивных файлов, например, в случае использования одного архивного каталога для разных экземпляров сервера.

    Каталог с архивом, указанный в команде, еще не создан. Создадим его.

  3. Выйдите из psql и запустите оболочку от имени пользователя postgres:

    archive_db=# \q
    [student@ServerName ~]$ sudo -iu postgres
  4. В домашнем каталоге пользователя postgres создайте каталог archive и перейдите в него:

    [postgres@ServerName ~]$ mkdir ~/archive && cd ~/archive

    Каталог должен принадлежать пользователю postgres, поскольку запись в него будет осуществляться самим экземпляром, запущенным от имени пользователя postgres.

  5. Перезапустите экземпляр сервера:

    [postgres@ServerName archive]$ pg_ctl restart -l ~/logfile
    waiting for server to shut down.... done
    server stopped
    waiting for server to start.... done
    server started

    Перезапуск потребовался после изменения параметра archive_mode.

  6. Подключитесь в psql к базе данных archive_db:

    [postgres@ServerName archive]$ psql -d archive_db
    psql (15.5)
    Type "help" for help.
  7. Проверьте, какой сегмент WAL используется в текущий момент:

    archive_db=# SELECT pg_walfile_name(pg_current_wal_lsn());
    pg_walfile_name
    --------------------------
    000000010000000000000002
    (1 row)

    Запись по-прежнему ведется во второй сегмент.

  8. Вставьте в таблицу some_table 1000 строк и посмотрите содержимое каталога ~/archive:

    archive_db=# INSERT INTO some_table SELECT 'Непрерывное архивирование!' FROM generate_series(1,1000);
    INSERT 0 1000
    archive_db=# \! ls -1 ~/archive

    После вставки 1000 строк архив по-прежнему пустой.

    Это означает, что записи WAL поместились в текущий сегмент.

    Вспомним, что копирование сегмента в ходе непрерывного архивирования выполняется при переключении на следующий сегмент.

  9. Проверьте, какой сегмент WAL используется в текущий момент:

    archive_db=# SELECT pg_walfile_name(pg_current_wal_lsn());
    pg_walfile_name
    --------------------------
    000000010000000000000002
    (1 row)

    Действительно, сегмент еще не сменился.

    Инициируем его смену вручную.

  10. Переключитесь вручную на следующий сегмент WAL и проверьте, какой сегмент стал использоваться после этого:

    archive_db=# SELECT pg_switch_wal();
    pg_switch_wal
    ---------------
    0/28623CA
    (1 row)
    archive_db=# SELECT pg_walfile_name(pg_current_wal_lsn());
    pg_walfile_name
    --------------------------
    000000010000000000000003
    (1 row)

    Теперь сегмент сменился. Предыдущий должен был быть скопирован в архив. Проверим это.

  11. Посмотрите содержимое каталога ~/archive:

    archive_db=# \! ls -1 ~/archive
    000000010000000000000002

    Сегмент скопирован. Непрерывное архивирование настроено.

Завершение​

Завершение на виртуальной машине Host1​

  1. Сбросьте настройки непрерывного архивирования:

    archive_db=# ALTER SYSTEM RESET archive_command;
    ALTER SYSTEM
    archive_db=# ALTER SYSTEM RESET archive_mode;
    ALTER SYSTEM
  2. Подключитесь к базе данных postgres и удалите базу данных archive_db:

    archive_db=# \c postgres
    You are now connected to database "postgres" as user "postgres".
    postgres=# DROP DATABASE archive_db;
    DROP DATABASE
  3. Выйдите из psql и перезапустите экземпляр сервера:

    postgres=# \q
    [postgres@ServerName archive]$ pg_ctl restart -l ~/logfile
    waiting for server to shut down.... done
    server stopped
    waiting for server to start.... done
    server started
  4. Удалите каталог archive:

[postgres@ServerName archive]$ cd ~ && rm -r archive
  1. Выйдите из оболочки, выполняемой от имени пользователя postgres:

    [postgres@ServerName ~]$ exit
    logout

Завершение на виртуальной машине Host2​

Удалите каталог archive:

[student@ServerName archive]$ cd ~ && rm -r archive

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

Вопрос 1

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

some_db=# SHOW max_slot_wal_keep_size;
max_slot_wal_keep_size
------------------------
-1
(1 row)

some_db=# SELECT pg_ls_dir('pg_wal');
pg_ls_dir
--------------------------
archive_status
000000010000000000000001
000000010000000000000002
000000010000000000000003
000000010000000000000004
000000010000000000000005
(3 rows)

some_db=# SELECT slot_name, slot_type, active, restart_lsn FROM pg_replication_slots;
slot_name   | slot_type | active | restart_lsn
--------------+-----------+--------+-------------
slot1        | physical  | f      | 0/3000000
slot2        | physical  | f      |
slot3        | physical  | t      | 0/4000000
(3 row)

Удалению каких сегментов WAL не препятствуют слоты репликации? Выберите все верные варианты ответа

Вопрос 2

Содержимое каталога с сегментами WAL представлено ниже:

[student@pangolin-prac-c51koi ~]$ ls -1 /wal
000000010000000000000005
000000010000000000000006
000000010000000000000007
000000010000000000000008.partial

Какое средство могло быть использовано для наполнения каталога /wal при условии, что оно было единственным и применялись стандартные правила именования сегментов WAL?

Вопрос 3

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

some_db=# SHOW archive_mode;
archive_mode
--------------
on
(1 row)

some_db=# SHOW archive_command;
archive_command
-----------------
cp %p /archive/%f
(1 row)

some_db=# SELECT pg_walfile_name(pg_current_wal_lsn());
pg_walfile_name
--------------------------
000000010000000000000004
(1 row)

Какие файлы могут находиться в каталоге /archive при условии, что создание файлов в нем выполняет только процесс archiver? Выберите все верные варианты ответа