PostgreSQL
Logical Replication: публикации и подписки
PostgreSQL 14 работает в production 3 года. Вышел PostgreSQL 16 с огромными улучшениями планировщика. Как обновиться без 8 часов downtime? В 2017 году это была нерешаемая задача. Сегодня: logical replication между pg14 и pg16 синхронизирует данные за несколько часов, переключение трафика - 30 секунд. Zalando обновляет Postgres на 500+ инстансах именно так. Logical replication - это инструмент, который делает PostgreSQL живым организмом, способным меняться без остановки.
- **Zalando** - zero-downtime major version upgrades через logical replication: обновление 500+ PostgreSQL инстансов с downtime менее 30 секунд на каждый
- **Stripe** - row-filter publications для GDPR: EU-данные реплицируются только в EU-датацентры, US - только в US. Фильтрация по region в PUBLICATION на уровне PostgreSQL
- **Supabase** - logical replication для point-in-time branching: создание ветки БД для разработки через subscription на production, актуальные данные без dump/restore
Logical vs Physical Replication
**Physical replication копирует весь кластер побайтово. Logical replication - только выбранные таблицы, в логическом формате (INSERT/UPDATE/DELETE).** Физическая быстрее и проще, но реплика должна быть identical версии PostgreSQL и архитектуры. Logical позволяет реплицировать между разными версиями, фильтровать таблицы, реплицировать в обе стороны.
| Характеристика | Physical (Streaming) | Logical |
|---|---|---|
| Единица репликации | Весь кластер | Отдельные таблицы/схемы |
| Версии PostgreSQL | Должны совпадать | Разные (в обе стороны) |
| Направление | Только primary→standby | Двунаправленная возможна |
| DDL (CREATE TABLE) | Автоматически | Не реплицируется |
| Объём WAL | Весь WAL | Только отмеченные таблицы |
| Standby - writeable? | Нет (read-only) | Да |
**Главные применения logical replication:** zero-downtime major upgrade (pg15 → pg16), репликация подмножества таблиц в analytics DB, bi-directional replication, шардинг через Citus, синхронизация данных между регионами.
Команда обновляет PostgreSQL 14 → 16 без downtime. Какой тип репликации позволяет это сделать?
PUBLICATION: что реплицировать
**PUBLICATION** определяет набор таблиц для логической репликации - это издатель. Можно публиковать все таблицы, конкретный список, или таблицы с фильтрацией по строкам (PostgreSQL 15+). Publication - объект на publisher-стороне (primary).
**DDL не реплицируется через logical replication.** Если на publisher добавлен столбец в таблицу - на subscriber нужно сделать ALTER TABLE вручную до применения изменений. Это главное ограничение по сравнению с physical replication.
PUBLICATION создана для таблицы `users`. На publisher выполнен `ALTER TABLE users ADD COLUMN last_login timestamptz`. Что нужно сделать на subscriber?
SUBSCRIPTION: подписка на изменения
**SUBSCRIPTION** - объект на subscriber-стороне, описывающий подключение к publisher и список publications. При создании subscription PostgreSQL автоматически копирует начальные данные (initial data copy) и затем начинает принимать поток изменений. Subscriber может быть полноценной writeable БД.
**`DROP SUBSCRIPTION` автоматически удаляет replication slot на publisher.** Это важно: в отличие от ручного удаления слота, DROP SUBSCRIPTION делает cleanup корректно. Если subscriber недоступен - нужно удалить слот на publisher вручную через `pg_drop_replication_slot()`.
Subscription создана с copy_data=true. Что происходит сразу после CREATE SUBSCRIPTION?
Selective Replication: фильтры строк и столбцов
**PostgreSQL 15+ позволяет фильтровать строки в PUBLICATION, 16+ - выбирать отдельные столбцы.** Это открывает архитектурные возможности: реплицировать только данные конкретного региона, маскировать PII-поля в analytics replica, реплицировать только активных пользователей для ML-задач.
**Использование в production:** Stripe реплицирует данные американских транзакций только в US-датацентры, европейских - в EU (GDPR compliance). Фильтрация по region в PUBLICATION гарантирует, что данные европейцев физически не покидают EU.
PUBLICATION создана с `WHERE (region = 'EU')`. Заказ с region='US' обновлён, region изменён на 'EU'. Что получит subscriber?
Ограничения Logical Replication
**Logical replication имеет принципиальные ограничения, которые нужно знать до выбора архитектуры.** Понимание ограничений позволяет избежать сюрпризов в production и выбрать правильный подход для конкретной задачи.
**Sequences - главная ловушка при bi-directional replication.** Если обе стороны генерируют serial ID - рано или поздно конфликт. Стандартные решения: разные диапазоны ID (A генерирует 1..500M, B генерирует 500M..1B), или UUID, или генерация только на одной стороне.
**Zero-downtime upgrade PostgreSQL 14→16** через logical replication: создать pg16, создать subscription на pg14, дождаться sync, переключить трафик. Единственное ограничение - нужно применить все DDL-изменения на pg16 вручную до старта subscription.
Logical replication - полная замена physical replication, просто более гибкая
Logical и physical replication решают разные задачи. Physical - HA и failover для всего кластера. Logical - избирательная репликация, cross-version upgrade, CDC. В production часто используют оба: physical для HA standby, logical для analytics replica или upgrade
Physical replication автоматически реплицирует DDL, sequences, системные каталоги. Logical - только DML для явно указанных таблиц. Failover через logical replication требует ручной синхронизации sequences и применения DDL - это сложно. Patroni для HA всегда строится поверх physical replication
Bi-directional logical replication между двумя датацентрами. Пользователь A вставляет запись с id=100 в DC1, одновременно пользователь B вставляет запись с id=100 в DC2. Что произойдёт?
Итоги
- **Logical vs physical**: logical реплицирует избранные таблицы между любыми версиями, physical - весь кластер побайтово только между идентичными версиями
- **PUBLICATION** (publisher) определяет что реплицировать. **SUBSCRIPTION** (subscriber) - куда и как подключаться
- **DDL не реплицируется** - главное ограничение. ALTER TABLE нужно применять на subscriber вручную синхронно с publisher
- **Row/column filtering** (pg15+/pg16+) позволяет реплицировать только нужные строки и столбцы - GDPR compliance, analytics без PII
- **Sequences не реплицируются** - при bi-directional replication обязательны UUID или разные диапазоны ID
Связанные темы
Logical replication строится поверх WAL и logical decoding:
- LISTEN/NOTIFY и Logical Decoding — Logical replication использует те же replication slots и output plugins что и CDC через pg_recvlogical/Debezium
- Streaming Replication — Комплементарная технология: physical для HA standby + failover, logical для cross-version upgrade и analytics replica
- Обновление PostgreSQL — Zero-downtime major upgrade через logical replication - стандартный подход для больших production баз
Вопросы для размышления
- Нужно реплицировать таблицу `transactions` в analytics PostgreSQL без PII-полей (card_number, user_name). Как настроить PUBLICATION чтобы гарантированно не передавать эти поля? Что изменится если UPDATE меняет только non-PII поле?
- После настройки bi-directional replication оба датацентра используют SERIAL для ID. Через неделю - конфликты. Как переделать схему чтобы конфликты были невозможны без остановки приложения?
- Zero-downtime upgrade pg14→pg16 через logical replication. На pg14 таблица имеет 50 столбцов, 3 из которых добавили на прошлой неделе. Как убедиться что pg16 готов к приёму subscription прежде чем её создать?