Репликация: master-replica, синхронная и асинхронная, read replicas

↑ 6.1 Масштабирование и надёжность данных · → Следующая

Желательно~4 мин чтенияУровень: senior

Зачем это на собесе

Репликация — база отказоустойчивости и масштабирования чтения. Спрашивают виды, задержку и проблемы согласованности.

Зачем

  • отказоустойчивость: при падении основного узла есть копия (failover);
  • масштабирование чтения: запросы разносятся на реплики;
  • изоляция нагрузок: отчёты и бэкапы на реплике;
  • территориальная близость и DR (реплика в другом регионе).

Репликация не заменяет бэкапы: удаление или порча данных реплицируются мгновенно.

Виды

Физическая (streaming)Логическая
Что передаётизменения WAL на уровне блоковизменения строк (INSERT/UPDATE/DELETE)
Репликаточная копия всего кластера, read-only (hot standby)любая схема, выборочные таблицы, другая версия БД
ПрименениеHA, read replicasмиграции версий, CDC, интеграции, частичная репликация
Ограниченияодинаковая major-версия, вся БДнужен PK/REPLICA IDENTITY, DDL не передаётся, последовательности вручную

PostgreSQL: физическая pg_basebackup + primary_conninfo; логическая — CREATE PUBLICATION / CREATE SUBSCRIPTION.

-- на основном (логическая)
CREATE PUBLICATION pub_orders FOR TABLE orders, order_items;
-- на подписчике
CREATE SUBSCRIPTION sub_orders CONNECTION 'host=pg1 dbname=app user=repl' PUBLICATION pub_orders;

Синхронная и асинхронная

АсинхроннаяСинхронная
Подтверждение коммитапосле записи на основномпосле подтверждения реплики(ами)
Задержка записиминимальнаявыше (RTT до реплики)
Потеря данных при сбоевозможна (RPO > 0)нет (RPO = 0) при сохранности реплики
Доступность записине зависит от репликпадает, если нет синхронной реплики

PostgreSQL: synchronous_standby_names = 'FIRST 1 (replica1, replica2)' или ANY 1 (...) (кворум), synchronous_commit (on, remote_write, remote_apply, local, off). Компромисс: кворумная синхронность (ANY 1 из 2) балансирует надёжность и доступность.

Лаг репликации и read-your-writes

Асинхронные реплики отстают (миллисекунды–секунды, под нагрузкой — минуты). Последствия: пользователь изменил данные и не видит их при чтении с реплики.

Решения:

  • читать только с основного после записи (на время сессии/запроса) — «sticky»;
  • отслеживать LSN: клиент запоминает позицию записи, реплика отдаёт данные, если pg_last_wal_replay_lsn() >= lsn;
  • synchronous_commit = remote_apply для критичных операций;
  • маршрутизация: критичное чтение — на primary, отчёты — на реплику;
  • мониторинг лага: pg_stat_replication (write_lag, flush_lag, replay_lag), pg_last_xact_replay_timestamp().

Конфликты на реплике (recovery conflicts): долгие запросы на реплике конфликтуют с применением WAL (max_standby_streaming_delay, hot_standby_feedback — но он раздувает основной).

Топологии

  • один primary + N реплик (цепочки/каскад: реплика питает другие реплики);
  • multi-master (BDR, Citus, Galera-подобные): конфликты записи, сложность;
  • Active-passive (резерв) и active-active (запись в нескольких регионах, нужны разрешение конфликтов и идемпотентность).

Failover и promote

  • ручной: pg_ctl promote / SELECT pg_promote();
  • автоматический: Patroni (etcd/Consul/ZooKeeper как DCS), repmgr, pg_auto_failover, облачные (RDS Multi-AZ, Cloud SQL HA);
  • задачи: выбор наиболее актуальной реплики, fencing старого основного (защита от split-brain), обновление адресов (VIP, DNS, HAProxy/PgBouncer), перевод остальных реплик на нового лидера (pg_rewind);
  • учения: регулярные тесты переключения.

В приложении

  • строка подключения к primary (через HAProxy/PgBouncer/VIP) и отдельная к реплике для чтения; в Npgsql Target Session Attributes=primary / prefer-standby, мульти-хост строки подключения;
  • учёт ошибок при failover: повторы идемпотентных операций, короткие retry, transient fault handling;
  • EF Core: два DbContext (чтение/запись) или перехватчик маршрутизации.

Другие БД

СистемаРепликация
MySQLbinlog (асинхронная, полусинхронная, Group Replication)
MongoDBreplica set, выборы, writeConcern: majority
Redisасинхронная + Sentinel/Cluster
ClickHouseReplicatedMergeTree через Keeper (мультимастер)
KafkaISR-реплики партиций
Cassandraleaderless, настраиваемый кворум

Вопросы с ответами