SQLLab
Все статьи

Репликация PostgreSQL: streaming replication и read replicas

Настройка streaming replication в PostgreSQL: primary/standby, pg_basebackup, read replicas, синхронная репликация, мониторинг лага. Практический гайд.

23 марта 2026 г.·5 мин чтения·

Репликация PostgreSQL позволяет создавать копии базы данных в реальном времени. Используется для отказоустойчивости (HA), горизонтального масштабирования чтения и резервного копирования.

Типы репликации

Streaming replication (физическая)
├── Асинхронная — primary не ждёт подтверждения standby (быстро, возможна потеря данных)
└── Синхронная  — primary ждёт подтверждения (надёжно, +задержка)

Logical replication
└── Репликация на уровне строк (можно выбирать таблицы, разные версии PG)

Настройка: Primary сервер

postgresql.conf

# Включить WAL для репликации
wal_level = replica          # минимум для streaming replication

# Сколько standby могут подключаться одновременно
max_wal_senders = 5

# Хранить WAL пока standby не получит
wal_keep_size = 1GB          # или max_wal_size

# Синхронная репликация (опционально)
# synchronous_standby_names = 'standby1'

# Для горячего резерва (read queries на standby)
hot_standby = on

pg_hba.conf — разрешить репликацию

# Разрешить подключение standby-серверов для репликации
# TYPE  DATABASE    USER        ADDRESS         METHOD
host    replication replicator  10.0.0.2/32     md5
host    replication replicator  10.0.0.3/32     md5

Создать пользователя для репликации

CREATE USER replicator REPLICATION LOGIN PASSWORD 'strong_password';
-- REPLICATION — специальная роль, только для репликации

Настройка: Standby сервер

Клонировать Primary

# На standby-сервере: скопировать данные с primary
pg_basebackup \
  -h 10.0.0.1 \           # IP primary
  -U replicator \
  -D /var/lib/postgresql/data \  # директория данных standby
  -P \                     # прогресс
  -Xs \                    # включить WAL в бэкап (streaming)
  -R                       # создать standby.signal + postgresql.auto.conf

Флаг -R автоматически создаёт:

  • standby.signal — файл, который говорит PostgreSQL работать в режиме standby
  • postgresql.auto.conf — параметры подключения к primary

postgresql.auto.conf (создаётся автоматически)

primary_conninfo = 'host=10.0.0.1 port=5432 user=replicator password=strong_password application_name=standby1'

Запустить Standby

# Запустить PostgreSQL — он автоматически войдёт в режим recovery
systemctl start postgresql

# Проверить статус
psql -c "SELECT pg_is_in_recovery();"
-- t  ← standby в режиме recovery (read-only)

Мониторинг репликации

На Primary

-- Статус всех подключённых standby
SELECT
    application_name,
    state,              -- streaming / catchup
    sent_lsn,          -- отправлено primary
    write_lsn,         -- записано на standby
    flush_lsn,         -- сброшено на диск standby
    replay_lsn,        -- применено standby
    pg_wal_lsn_diff(sent_lsn, replay_lsn) AS lag_bytes,
    write_lag,         -- задержка записи
    flush_lag,         -- задержка сброса
    replay_lag         -- задержка применения
FROM pg_stat_replication;

На Standby

-- Статус standby
SELECT * FROM pg_stat_wal_receiver;

-- Отставание в байтах
SELECT pg_wal_lsn_diff(pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn()) AS lag_bytes;

-- Время последнего применённого WAL
SELECT now() - pg_last_xact_replay_timestamp() AS lag_seconds;

Read Replicas: маршрутизация запросов

# Django: несколько баз данных
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'HOST': '10.0.0.1',  # Primary (write)
        'NAME': 'myapp',
        ...
    },
    'replica': {
        'ENGINE': 'django.db.backends.postgresql',
        'HOST': '10.0.0.2',  # Standby (read)
        'NAME': 'myapp',
        ...
    }
}

DATABASE_ROUTERS = ['myapp.routers.PrimaryReplicaRouter']
# routers.py
class PrimaryReplicaRouter:
    def db_for_read(self, model, **hints):
        return 'replica'  # Читать с реплики

    def db_for_write(self, model, **hints):
        return 'default'  # Писать в primary

    def allow_relation(self, obj1, obj2, **hints):
        return True

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        return db == 'default'  # Миграции только на primary

Синхронная репликация

# postgresql.conf на Primary
synchronous_standby_names = 'FIRST 1 (standby1, standby2)'
# или
synchronous_standby_names = 'standby1'

# ANY — хотя бы один из standby должен подтвердить
synchronous_standby_names = 'ANY 1 (standby1, standby2)'
-- Уровни синхронности для транзакции
SET synchronous_commit = on;       -- подождать flush на standby (безопасно)
SET synchronous_commit = remote_write;  -- подождать write (быстрее, менее надёжно)
SET synchronous_commit = local;    -- не ждать standby (асинхронно)
SET synchronous_commit = off;      -- даже не ждать local flush

Логическая репликация

-- PRIMARY: создать publication
CREATE PUBLICATION mypub FOR TABLE users, orders;
-- или все таблицы:
CREATE PUBLICATION mypub FOR ALL TABLES;

-- STANDBY/другой сервер: создать subscription
CREATE SUBSCRIPTION mysub
    CONNECTION 'host=10.0.0.1 dbname=myapp user=replicator password=...'
    PUBLICATION mypub;

-- Проверить статус
SELECT * FROM pg_stat_subscription;

Когда использовать логическую репликацию:

  • Разные версии PostgreSQL (например, миграция с PG 14 на PG 16)
  • Нужно реплицировать только часть таблиц
  • Двунаправленная репликация (multi-master)
  • ETL в аналитическую БД

Промоция Standby (failover)

# Ручная промоция standby в primary
pg_ctl promote -D /var/lib/postgresql/data
# или
psql -c "SELECT pg_promote();"

# Проверить что стал primary
psql -c "SELECT pg_is_in_recovery();"
-- f  ← теперь primary

Для автоматического failover используют:

  • Patroni — высокодоступный кластер с автофейловером
  • repmgr — управление репликацией и фейловером
  • pg_auto_failover — от Microsoft, простая настройка

Docker Compose пример

services:
  postgres-primary:
    image: postgres:16
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: myapp
    command: >
      postgres
      -c wal_level=replica
      -c max_wal_senders=5
      -c hot_standby=on

  postgres-standby:
    image: postgres:16
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: secret
    depends_on:
      - postgres-primary
    # Требует дополнительных скриптов для pg_basebackup и standby.signal

Итог

Streaming (физическая)Logical
КопируетВесь кластерВыбранные таблицы
Разные версии PG
DDLАвтоматически❌ (ручное)
ЗадержкаМинимальнаяЧуть больше
ПрименениеТолько PGЛюбая СУБД

Streaming replication — стандарт для HA и read replicas. Логическая репликация — для специальных сценариев: миграция версий, частичная репликация, multi-master.

Похожие статьи

Попробуй на практике

Тренажёр с реальными задачами — бесплатно и без регистрации

Открыть тренажёр →