Как настроить потоковую репликацию в PostgreSQL
Продвинутое4 минРедакция Innovialabs
Коротко
Разрешите репликацию на primary, создайте роль и слот, разверните standby через pg_basebackup с флагом -R, следите за отставанием в pg_stat_replication, а переключение делайте через pg_promote или автоматически с Patroni.
Короткий ответ
Потоковая репликация передаёт журнал предзаписи (WAL) с основного сервера (primary) на один или несколько standby почти в реальном времени. Standby можно использовать для чтения и как готовую замену при аварии.
Порядок настройки:
- Разрешить подключения для репликации на primary.
- Создать роль и слот репликации.
- Скопировать данные на standby через
pg_basebackup. - Запустить standby и проверить отставание.
- Продумать маршрутизацию чтения и сценарий failover.
Важно: репликация — это не резервная копия. Ошибочный DELETE мгновенно уедет на все реплики, поэтому бэкапы с point-in-time recovery нужны всё равно.
Шаг 1. Настройка primary
В postgresql.conf:
listen_addresses = '*'
wal_level = replica
max_wal_senders = 10
max_replication_slots = 10
wal_level = replica — значение по умолчанию в современных версиях, но его стоит проверить. Изменение listen_addresses и wal_level требует перезапуска.
Создайте роль для репликации и слот:
CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'сложный_пароль';
SELECT pg_create_physical_replication_slot('standby1');
Разрешите подключение в pg_hba.conf только с адреса реплики:
host replication replicator 10.0.0.12/32 scram-sha-256
После правки pg_hba.conf достаточно SELECT pg_reload_conf();.
Шаг 2. Развёртывание standby
На сервере реплики остановите PostgreSQL и очистите каталог данных. Затем скопируйте данные с primary:
pg_basebackup -h 10.0.0.11 -U replicator \
-D /var/lib/postgresql/data \
-X stream -S standby1 -R -P
-X stream— передавать WAL во время копирования;-S standby1— использовать созданный слот;-R— создать файлstandby.signalи записатьprimary_conninfoвpostgresql.auto.conf.
Проверьте, что в postgresql.auto.conf есть primary_slot_name = 'standby1', и запустите сервер. Параметр hot_standby = on (по умолчанию) разрешает читать с реплики.
Зачем нужны слоты и чем они опасны
Слот репликации заставляет primary хранить WAL, пока standby его не получит. Без слота реплика после долгого простоя может отстать безвозвратно и потребует новой копии.
Обратная сторона: если реплика выключена навсегда, а слот остался, WAL копится на primary до заполнения диска. Поэтому:
- удаляйте слоты выведенных реплик:
SELECT pg_drop_replication_slot('standby1');; - ограничьте объём через
max_slot_wal_keep_size(доступен в современных версиях); - мониторьте размер удерживаемого WAL.
Шаг 3. Мониторинг отставания
На primary:
SELECT client_addr, state, replay_lag,
pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS lag_bytes
FROM pg_stat_replication;
SELECT slot_name, active,
pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) AS retained_bytes
FROM pg_replication_slots;
На standby — время с последней применённой транзакции:
SELECT now() - pg_last_xact_replay_timestamp() AS replay_delay;
Этот показатель растёт и при отсутствии записей на primary, поэтому оценивайте его вместе с lag_bytes. Выведите метрики в систему мониторинга (например, Prometheus с postgres_exporter) и настройте алерты на отставание, неактивные слоты и отключение реплики.
Шаг 4. Чтение с реплик
Реплики разгружают primary от отчётов, аналитики и тяжёлых выборок. Варианты маршрутизации:
- в приложении — два пула подключений: запись на primary, чтение на реплику;
- через libpq — несколько хостов в строке подключения и параметр
target_session_attrs(read-writeдля записи,read-onlyилиprefer-standbyв новых версиях); - через прокси — HAProxy или Pgpool-II.
Помните про асинхронность: только что записанные данные могут ещё не появиться на реплике. Чтение «своих» изменений (например, сразу после сохранения формы) направляйте на primary. Если потеря последних транзакций при аварии недопустима, рассмотрите синхронную репликацию через synchronous_standby_names — ценой задержки записи.
Шаг 5. Failover
Вручную
- Убедитесь, что primary действительно недоступен, и изолируйте его, чтобы он не вернулся как второй primary (split-brain).
- На standby выполните
SELECT pg_promote();илиpg_ctl promote. - Переключите приложение: DNS, виртуальный IP или строку подключения.
- Старый primary верните только как реплику — через
pg_rewindили новыйpg_basebackup.
С Patroni
Patroni управляет кластером автоматически: хранит информацию о лидере в DCS (etcd, Consul или ZooKeeper), следит за здоровьем узлов и при аварии продвигает лучшую реплику. Перед кластером обычно ставят HAProxy, который проверяет REST API Patroni (эндпоинты /primary и /replica) и направляет трафик на нужный узел.
Полезные команды:
patronictl -c /etc/patroni.yml list
patronictl -c /etc/patroni.yml switchover
Плановый switchover регулярно проверяйте на тестовом стенде — failover, который ни разу не запускали, нельзя считать рабочим. Подробности в документации PostgreSQL.