Настройка потоковой реплики PostgreSQL с помощью pg_basebackup
Оглавление
Настройка источника
На источнике создаём пользователя replication
с паролем при помощи команды, запущенной под пользователем postgres
:
$ createuser --replication -P replication
Для генерации надёжного случайного пароля можно воспользоваться утилитой pwgen
из одноимённого пакета.
Прописываем в файл /etc/postgresql/13/main/pg_hba.conf
доступ для пользователя replication
с IP-адреса будущей реплики:
host replication all 10.2.88.23/32 md5
Уже настроенные по умолчанию строчки для пользователя replication
можно закомментировать, т.к. репликация будет работать и без них:
#local replication all peer
#host replication all 127.0.0.1/32 md5
#host replication all ::1/128 md5
Для применения нового файла /etc/postgresql/13/main/pg_hba.conf
достаточно перезагрузить PostgreSQL:
# systemctl reload postgresql
Далее нужно проверить конфигурацию сервера в файле /etc/postgresql/13/main/postgresql.conf
следующим образом:
listen_addresses = '*'
wal_level = replica
max_wal_senders = 10
max_replication_slots = 10
hot_standby = on
hot_standby_feedback = on
Значение в опция listen_addresses
должно допускать подключение с IP-адреса будущей реплики.
Опция wal_level
должна иметь значение replica
или logical
, но первое значение предпочтительнее, т.к. журналы имеют меньший объём, но содержат всю информацию, необходимую для работы потоковой репликации.
Опции max_wal_senders
и max_replication_slots
ограничивают количество процессов, отдающих изменения в журналах репликации на реплики, и максимальное количество подключений со стороны реплик.
Опция hot_standby
позволяет реплике отменять запросы, которые пытается выполнить источник, если эти запросы не могут быть выполнены достаточно быстро на реплике, что может повлечь значительное отставание реплики от источника. Подробности см. в документации: Администрирование сервера / Администрирование сервера / Отказоустойчивость, балансировка нагрузки и репликация
Опция hot_standby_feedback
не позволяет реплике удалять устаревшие записи в процессе выполнения операции VACUUM, если они ещё присутствуют на источнике.
К счастью, опции wal_level
, max_wal_senders
, max_replication_slots
, hot_standby
в конфигурации по умолчанию уже имеют значения, подходящие для потоковой репликации. Если же значения опций пришлось изменить, то может потребоваться перезапуск PostgreSQL:
# systemctl restart postgresql
Настройка реплики
Файлы конфигурации реплики стоит отредактировать так, чтобы они повторяли таковые на источнике. Это будет особенно полезно, если понадобится поменять серверы ролями и переключить репликацию в обратном направлении.
Останавливаем реплику:
# systemctl stop postgresql
Удаляем на реплике имеющиеся файлы баз данных:
# rm -R /var/lib/postgresql/13/main/*
Выполняем съём резервной копии данных на источнике с помощью утилиты pg_basebackup
от имени пользователя postgres
:
$ pg_basebackup -h 10.2.88.16 -U replication -D /var/lib/postgresql/13/main --wal-method=stream --write-recovery-conf
После завершения съёма резервной копии запускаем PostgreSQL на реплике:
# systemctl start postgresql
Отслеживание состояния репликации
Следить за состоянием репликации на источнике можно с помощью таблицы pg_stat_replication
, например, запустив от имени пользователя postgres
следующую команду:
$ watch 'psql -xc "SELECT * FROM pg_stat_replication;"'
Информацию об отставании реплик можно увидеть именно на источнике.
Аналогичным образом за состоянием репликации можно следить на реплике с помощью таблицы pg_stat_wal_receiver
, например, запустив от имени пользователя postgres
такую команду:
$ watch 'psql -xc "SELECT * FROM pg_stat_wal_receiver;"'
Отсоединение реплики от источника
При необходимости поменять источник и реплику местами нужно сначала остановить изменение данных на источнике.
Для этого сначала нужно заблокировать в файле /etc/postgresql/13/main/pg_hba.conf
возможность подключения для всех пользователей, кроме пользователя replication
, закомментировав соответствующие строки. Применить изменения можно с помощью следующей команды:
# systemctl reload postgresql
Далее нужно отключить уже установленные подключения, отменив текущие выполняемые через них запросы:
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE pid <> pg_backend_pid()
AND usename NOT IN ('postgres', 'replication');
Далее убедиться, что реплика догнала источник, например, при помощи следующей команды, запущенной от пользователя postgres
:
$ watch 'psql -xc "SELECT * FROM pg_stat_replication;"'
Теперь можно остановить источник:
# systemctl stop postgresql
Осталось только переключить реплику в режим самостоятельной работы, выполнив на ней команду от имени пользователя postgres
:
$ pg_ctlcluster 13 main promote
Для настройки реплики на бывшем источники можно воспользоваться утилитой pg_basebackup
так, как это было описано выше.
Решение проблем
Если PostgreSQL на реплике завершил свою работу с сообщением об ошибке "requested WAL segment has already been removed", то на источнике произошло большое количество изменений, которое реплика не успела получить и применить. Для решения проблемы нужно указать на источнике объём сегментов WAL, который должен храниться на диске, с помощью опции wal_keep_size
. Значение указывается в мегабайтах. Если оно уже указано, то его следует увеличить. Для применения изменений достаточно перезагрузить PostgreSQL:
# systemctl reload postgresql
Реплику часто используют для снятия нагрузки с основного сервера, выполняя на реплике долгие аналитические запросы или резервное копирование данных. Процесс резервного копирования данных может завершиться аварийно с сообщением об ошибке следующего вида:
pg_dump: error: Dumping the contents of table "core_embedding" failed: PQgetResult() failed.
pg_dump: error: Error message from server: ERROR: canceling statement due to conflict with recovery
DETAIL: User was holding a relation lock for too long.
pg_dump: error: The command was: COPY public.core_embedding (id, date_created, embedding, photo_id, version_id) TO stdout;
Ошибки "canceling statement due to conflict with recovery" и "User was holding a relation lock for too long." говорят о том, что реплика слишком долго пыталась удержать от очистки на исходном сервере строки, подлежащие резервному копированию. Время удержания строк, подлежащих очистке, настраивается с помощью опций max_standby_archive_delay
и max_standby_streaming_delay
. По умолчанию они обе настроены на удержание в течение 30 секунд. Для успешного выполнения резервного копирования можно попробовать увеличить значения этих опций.