Репликация: потоковая и hot standby

Рейтинг: 67.6% · 8 голосов
Подробный курс по PostgreSQL: SQL по демобазе, типы данных и JSONB, индексы, транзакции и MVCC, VACUUM, EXPLAIN и планировщик, роли и привилегии, репликация, бэкап, настройка под нагрузку и под 1С. Актуально на 2026.
Ответить
Аватара пользователя
Egor_DBA
Сообщения: 47
Зарегистрирован: 11 май 2026, 05:31

Репликация: потоковая и hot standby

Сообщение Egor_DBA »

Оглавление курса (47)
  1. Что такое PostgreSQL: история, философия, где применяется
  2. Урок 1. Что нового в PostgreSQL 15 и далее (15 -> 16 -> 17)
  3. Установка и первый запуск: Linux, Windows, Docker
  4. psql детально: метакоманды и работа в консоли
  5. Демобаза Авиаперевозки Postgres Pro: структура и развёртывание
  6. SELECT: проекция, фильтрация, сортировка
  7. Транзакции и ACID
  8. Уровни изоляции транзакций: Read Committed, Repeatable Read, Serializable
  9. Соединения таблиц (JOIN)
  10. Агрегация: GROUP BY, HAVING, GROUPING SETS
  11. Подзапросы и CTE (WITH), рекурсия
  12. Оконные функции
  13. Изменение данных: INSERT/UPDATE/DELETE, UPSERT, MERGE
  14. Числовые и булевы типы, NULL и трёхзначная логика
  15. Строки, текст, дата и время, таймзоны
  16. Массивы, диапазоны, enum, составные типы
  17. JSON и JSONB: операторы и индексация
  18. DDL: CREATE TABLE, схемы, ALTER
  19. Ограничения целостности
  20. Представления и материализованные представления
  21. Последовательности, IDENTITY, генерируемые столбцы
  22. Индексы: B-tree и когда индекс не используется
  23. Типы индексов: Hash, GiST, SP-GiST, GIN, BRIN
  24. Продвинутые индексы: частичные, по выражению, покрывающие
  25. Обслуживание индексов и таблиц: bloat, REINDEX, CONCURRENTLY
  26. Полнотекстовый поиск
  27. Роли и пользователи
  28. Привилегии: GRANT/REVOKE
  29. Row-Level Security и безопасность данных
  30. Подключение приложения: pg_hba.conf, SSL, пулы соединений
  31. Серверное программирование: функции и процедуры
  32. Триггеры и события
  33. Архитектура PostgreSQL: процессы и память
  34. MVCC: версии строк и видимость
  35. VACUUM, autovacuum, freeze и wraparound
  36. WAL, контрольные точки и долговечность
  37. Блокировки и взаимоблокировки
  38. Планировщик запросов
  39. EXPLAIN и EXPLAIN ANALYZE: чтение планов
  40. Конфигурация сервера: ключевые параметры
  41. Настройка под нагрузку и под 1С
  42. Параллельные запросы и партиционирование
  43. Резервное копирование и восстановление
  44. Репликация: потоковая и hot standby (вы здесь)
  45. Логическая репликация и кластерные решения
  46. Внешние данные, расширения и сертификация
  47. Разбор планов запросов на explain.tensor.ru: глубокое чтение EXPLAIN ANALYZE
Урок 43. Репликация: потоковая и hot standby

Один сервер postgresql рано или поздно упрётся либо в нагрузку на чтение, либо в страх потерять данные при отказе диска. Репликация решает обе задачи сразу: мы запускаем второй сервер (реплику), который повторяет за основным каждое изменение байт в байт. В этом уроке разберём физическую потоковую репликацию: как primary отдаёт журнал, как standby его проигрывает, что такое слоты репликации и hot standby, чем синхронный режим отличается от асинхронного, и как пережить падение мастера через failover. Это фундамент отказоустойчивости, на котором потом строят и аналитические реплики, и кластеры под нагрузкой 1С.

Изображение

Как это работает

Сердце репликации в PostgreSQL - это WAL (Write-Ahead Log), журнал упреждающей записи. Любое изменение данных сначала пишется в WAL и только потом долетает до файлов таблиц. Идея проста: если у нас есть полный поток WAL-записей, мы можем взять копию базы и, прокатив по ней этот поток, получить точно такое же состояние. Физическая репликация именно это и делает - копирует журнал на блочном уровне, поэтому реплика бит в бит совпадает с мастером, включая физическое расположение строк.

Потоковая (streaming) репликация означает, что standby не ждёт, пока на мастере закроется целый файл сегмента журнала. Вместо этого процесс walreceiver на реплике держит постоянное TCP-соединение с процессом walsender на мастере и тянет WAL почти в реальном времени, маленькими порциями. Задержка обычно измеряется миллисекундами.

Hot standby - это режим, в котором реплику можно не только держать про запас, а ещё и читать с неё (SELECT). Запись на standby запрещена, но запросы на чтение разгружают мастер. Это включается параметром hot_standby = on (по умолчанию так и есть начиная с давних версий).

Теперь про надёжность доставки. По умолчанию репликация асинхронная: мастер подтвердил COMMIT клиенту, не дожидаясь, пока реплика этот коммит получит. Быстро, но при внезапной гибели мастера последние транзакции могут не доехать. Синхронная репликация (synchronous_commit) заставляет мастер ждать подтверждения от реплики перед ответом клиенту - так данные не теряются, но каждый коммит платит сетевой задержкой.

Отдельная важная штука - слоты репликации (replication slots). Без слота мастер не знает, докуда дочитала реплика, и может удалить ещё нужный ей кусок WAL (особенно если реплика отключалась). Слот - это закладка: мастер гарантирует, что не выбросит WAL, пока реплика его не заберёт. Обратная сторона - если реплика умерла навсегда, слот будет вечно держать журнал и однажды переполнит диск мастера. В PG 13+ это лечится параметром max_slot_wal_keep_size, который ставит верхний предел.

SQL и примеры

Сначала готовим мастер. В postgresql.conf задаём уровень журналирования и лимиты на число walsender и слотов.

Код: Выделить всё

-- параметры на primary (postgresql.conf)
wal_level = replica
max_wal_senders = 10
max_replication_slots = 10
hot_standby = on
Создаём роль для репликации и разрешаем ей подключаться в pg_hba.conf.

Код: Выделить всё

CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'strong_pw';
-- в pg_hba.conf:
-- host replication replicator 10.0.0.0/24 scram-sha-256
Создаём слот, чтобы мастер берёг журнал для будущей реплики.

Код: Выделить всё

SELECT * FROM pg_create_physical_replication_slot('standby1');
Снимаем базовую копию мастера утилитой pg_basebackup. Флаг -R сразу пишет standby.signal и строку подключения в конфиг, а --slot привязывает копию к нашему слоту.

Код: Выделить всё

pg_basebackup -h 10.0.0.1 -U replicator -D /var/lib/pgdata \
  -X stream -R --slot=standby1 -C
После запуска standby проверяем картину со стороны мастера. Поле replay_lsn показывает, докуда реплика проиграла журнал, а sync_state - синхронная она или нет.

Код: Выделить всё

SELECT client_addr, state, sent_lsn, replay_lsn, sync_state
FROM pg_stat_replication;
Оценим отставание реплики в байтах - сколько журнала мастер уже сгенерировал, но реплика ещё не проиграла. Полезно для мониторинга.

Код: Выделить всё

SELECT client_addr,
       pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS lag_bytes
FROM pg_stat_replication;
Включим синхронную репликацию: мастер будет ждать подтверждения от реплики по имени standby1 (имя задаётся через application_name в строке подключения standby).

Код: Выделить всё

-- на primary
ALTER SYSTEM SET synchronous_standby_names = 'standby1';
SELECT pg_reload_conf();
На самой реплике видно, что она в режиме восстановления, а текущую точку проигрывания покажет pg_last_wal_replay_lsn.

Код: Выделить всё

SELECT pg_is_in_recovery();          -- true на standby
SELECT pg_last_wal_replay_lsn();     -- докуда проиграли WAL
Failover - продвижение реплики в мастер, когда старый primary умер. После promote сервер выходит из режима восстановления и принимает запись.

Код: Выделить всё

-- на standby (через утилиту pg_ctl)
pg_ctl promote -D /var/lib/pgdata
-- или SQL-функцией:
SELECT pg_promote();
Демобаза тут участвует косвенно: на hot standby можно гонять тяжёлую аналитику, не трогая мастер. Например, отчёт по загрузке рейсов читается с реплики.

Код: Выделить всё

-- читаем с реплики, мастер не нагружаем
SELECT f.flight_no, count(*) AS passengers
FROM bookings.boarding_passes bp
JOIN bookings.ticket_flights tf
  ON tf.ticket_no = bp.ticket_no AND tf.flight_id = bp.flight_id
JOIN bookings.flights f ON f.flight_id = bp.flight_id
GROUP BY f.flight_no
ORDER BY passengers DESC
LIMIT 10;
Частые грабли
  • Слот без присмотра. Мёртвая реплика держит слот, мастер копит WAL и забивает диск под ноль. Мониторьте pg_replication_slots и ставьте max_slot_wal_keep_size.
  • Синхронная реплика в единственном числе. Если synchronous_standby_names указывает на одну реплику и она упала, мастер встанет колом на коммитах, ожидая подтверждения. Держите минимум две синхронные кандидатуры или используйте ANY 1 (standbyA, standbyB).
  • Конфликты на hot standby. Долгий SELECT на реплике может быть отменён, потому что мастер прислал VACUUM, удаливший нужные строки (ошибка canceling statement due to conflict with recovery). Лечится hot_standby_feedback = on или max_standby_streaming_delay.
  • Промоутнули мастер, не убив старый. Два сервера, оба думают, что они primary - это split-brain и расхождение данных. Перед promote убедитесь, что старый мастер реально мёртв (фенсинг).
  • Старый recovery.conf. В PG 12 этот файл упразднили: настройки переехали в postgresql.auto.conf, а сигналом служит файл standby.signal. Инструкции из древних статей под PG 11 уже не работают.
  • Забыли про timeline. После failover у новой ветки журнала своя временная линия. Чтобы старый мастер вернулся как реплика, его обычно надо переинициализировать через pg_rewind, а не просто перезапустить.
Мини-лаба
  • Поднимите два кластера PostgreSQL 15 на одной машине: основной на порту 5432, будущая реплика на 5433 (разные каталоги данных).
  • На мастере задайте wal_level = replica, max_wal_senders = 10, создайте роль replicator с правом REPLICATION и пропишите доступ для replication в pg_hba.conf.
  • Создайте физический слот pg_create_physical_replication_slot('standby1') и снимите копию: pg_basebackup -h localhost -p 5432 -U replicator -D pgdata_standby -X stream -R --slot=standby1.
  • Запустите реплику на 5433 и убедитесь в pg_stat_replication на мастере, что появилась строка с state = streaming.
  • Вставьте на мастере тестовую таблицу с парой строк, затем выполните тот же SELECT на реплике - данные должны приехать. Проверьте, что INSERT на реплике падает с ошибкой read-only.
  • Включите синхронный режим (synchronous_standby_names = 'standby1', reload), сделайте коммит и посмотрите sync_state в pg_stat_replication.
  • Остановите мастер, выполните pg_promote() на реплике, убедитесь, что pg_is_in_recovery() вернул false и запись теперь разрешена.
Контрольные вопросы
  • Почему физическая репликация требует именно WAL и что значит "реплика бит в бит совпадает с мастером"?
  • Чем потоковая доставка WAL отличается от доставки через архив сегментов и в чём выигрыш по задержке?
  • Зачем нужен слот репликации и какой ценой он защищает реплику от потери журнала?
  • В каком случае синхронная репликация может полностью заблокировать запись на мастере и как это предотвратить?
  • Что такое split-brain при failover и какие меры (фенсинг, pg_rewind) защищают от него?
  • Какую проблему решает hot_standby_feedback и за что мы при этом платим на стороне мастера?
👍5 ❤️3 🔥3 😄 🤔
Аватара пользователя
clickhouseveteran
Сообщения: 1
Зарегистрирован: 23 май 2026, 06:39

Re: Репликация: потоковая и hot standby

Сообщение clickhouseveteran »

А если реплику использовать чисто под отчёты 1С, синхронный режим вообще не нужен? Боюсь что коммиты на мастере просядут по скорости.
👍2 ❤️2 🔥 😄 🤔
Аватара пользователя
mgrant78
Сообщения: 1
Зарегистрирован: 19 май 2026, 12:10

Re: Репликация: потоковая и hot standby

Сообщение mgrant78 »

Поймал на проде canceling statement due to conflict with recovery, помог hot_standby_feedback=on. Но потом заметил что на мастере мусора в таблицах стало больше, vacuum как будто ленивее чистит. Это нормально или я что-то сломал?
👍 ❤️ 🔥 😄 🤔
Ответить
← Предыдущая глава
Резервное копирование и восстановление
Следующая глава →
Логическая репликация и кластерные решения

Все главы курса «PostgreSQL: от первого запроса до продакшена»

Поделиться темой: ✈ Telegram VK
  • Похожие темы

Вернуться в «PostgreSQL: от первого запроса до продакшена»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость