Чем отличается от физической
Физическая репликация копирует кластер байт-в-байт через WAL. Всё или ничего: та же версия, та же схема, нельзя писать на копии.
Логическая работает на уровне строк. Из того же WAL процесс логического декодирования восстанавливает «в таблице X строка с ключом K стала такой-то» и шлёт это подписчику как логическую операцию. Подписчик - обычный самостоятельный кластер: у него свои индексы, он принимает запись, может быть другой мажорной версии.
publisher subscriber
┌────────────────────────┐ ┌──────────────────┐
│ WAL (wal_level=logical) │ │ apply worker │
│ ↓ logical decoding │ ──строки──▶│ ↓ │
│ PUBLICATION (набор │ │ INSERT/UPDATE/ │
│ таблиц) │ │ DELETE локально │
└────────────────────────┘ └──────────────────┘
Минимальная настройка
На публикующем сервере нужен wal_level = logical (см. wal-level;
требует рестарта - это больше, чем replica, потому что в WAL добавляется
информация для декодирования строк).
-- на источнике
CREATE PUBLICATION pub_flights FOR TABLE flights;
-- на приёмнике (таблица flights должна уже существовать структурно)
CREATE SUBSCRIPTION sub_flights
CONNECTION 'host=primary dbname=lab user=rep password=...'
PUBLICATION pub_flights;
При создании подписки по умолчанию идёт начальная копия данных
(copy_data = true), затем поток догоняющих изменений. Прогресс видно в
pg_stat_subscription на приёмнике и pg_replication_slots на
источнике (под каждую подписку источник держит логический слот).
Что НЕ едет автоматически
Это главный источник сюрпризов. Логическая репликация везёт DML по перечисленным таблицам - и почти ничего больше:
- DDL не реплицируется.
ALTER TABLE ... ADD COLUMNна источнике не доедет; добавить колонку нужно руками на обеих сторонах, иначе apply встанет. - Последовательности (sequences) не синхронизируются - значение
serial/identity на приёмнике своё. После переключения легко словить конфликт первичного ключа. - TRUNCATE едет, только если включён в публикацию.
- Таблице нужна replica identity (обычно первичный ключ), иначе UPDATE/DELETE по ней не реплицируются.
Конфликты
Подписчик принимает запись и от своих клиентов тоже. Если прилетит изменение строки, которой локально уже нет (или есть с другим ключом), apply-воркер падает с конфликтом и встаёт - репликация по этой подписке стоит, пока конфликт не разрешат вручную. Поэтому «писать в обе стороны» без чёткого разделения ключей - прямая дорога к остановке (см. distributed-pitfalls).
Типичные применения: миграция между мажорными версиями без даунтайма, сбор нескольких баз в одно хранилище, репликация подмножества таблиц. Про сам журнал, из которого всё декодируется - streaming-replication.