О логической репликации
В PostgreSQL 10 появилась встроенная поддержка PUBLICATION и SUBSCRIPTION через логическую репликацию. У неё есть существенные ограничения — PostgreSQL не реплицирует:
- DDL-команды;
- данные о последовательностях (sequences);
- большие объекты (LOB, large objects).
Плагин cnpg для CloudNativePG закрывает первые два пункта. Если используете large objects — нужен «офлайн»-подход.
Миграция с почти нулевым простоем
Цель — свести к минимуму время простоя приложения по записи. В индустрии такие миграции называют «~0 cutover time» или flash-cut.
Стратегия — change data capture через непрерывную логическую репликацию из исходной БД в целевую под управлением CloudNativePG. Шаги успешной миграции:
- Полностью завершить первичную настройку.
- Убедиться, что целевая БД синхронизирована с исходной.
- Остановить запись из приложения.
- Дождаться, пока очередь изменений будет применена на приёмнике.
- Синхронизировать sequences.
- Удалить подписку и публикацию.
- Раскатить версию приложения, которая ходит в новую БД.
Плюсы подхода:
- этапы повторяемы — можно репетировать;
- учёба в «зелёной зоне» без давления на прод;
- можно точно измерить время cutover до релиза;
- подходит и для major-апгрейда самого PostgreSQL;
- безопасно — старая БД продолжает работать, если что-то пошло не так.
Первичная настройка миграции
День 0 — самый ответственный этап. Что нужно подготовить:
- сетевую связность от кластера CloudNativePG до исходной БД с правами суперпользователя;
- целевой кластер CloudNativePG, в который импортируется только схема (без данных);
PUBLICATIONв исходной БД;SUBSCRIPTIONв целевой БД;- проверку, что подписка реально работает.
Для простоты в примере используется суперпользователь, в проде — отдельный пользователь миграции с минимально необходимыми правами.
Основные сценарии
Техника «~0 cutover» применима, когда нужно:
- уйти с DBaaS в Kubernetes — Amazon RDS, Google Cloud SQL, Azure Database for PostgreSQL;
- переехать с виртуалок или bare metal в Kubernetes — любой PostgreSQL, доступный по сети;
- сменить Kubernetes-оператор — Zalando, Crunchy, Percona, StackGres;
- сделать major-апгрейд PostgreSQL — переезд существующего CloudNativePG на новую версию.
Пример миграции из AWS RDS
Перевозим PostgreSQL 16 из RDS в EKS.
Включаем логическую репликацию в RDS
- Создаём parameter group
rds-logical-replication. - Включаем
rds.logical_replication. - Применяем parameter group к нужной БД.
- Перезагружаем БД, чтобы
wal_levelсталlogical. - Убеждаемся, что есть сетевой доступ из Kubernetes-кластера.
Разворачиваем целевую БД
Секрет с суперпользователем:
kubectl create secret \
--dry-run=client -o yaml generic rds-superuser \
--from-literal=username=postgres \
--from-literal=password=AngusYoung1955Целевой кластер с импортом только схемы (schemaOnly: true):
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: angus
spec:
instances: 1
storage:
size: 50Gi
bootstrap:
initdb:
import:
type: microservice
schemaOnly: true
databases:
- app
source:
externalCluster: rds
externalClusters:
- name: rds
connectionParameters:
host: <HOST>.rds.amazonaws.com
user: postgres
dbname: app
password:
name: rds-superuser
key: passwordСоздаём публикацию
kubectl cnpg publication create angus \
--external-cluster rds \
--publication migration \
--all-tablesПод капотом:
CREATE PUBLICATION "migration" FOR ALL TABLES;Создаём подписку
kubectl cnpg subscription create angus \
--external-cluster rds \
--publication migration \
--subscription migrationCloudNativePG соберёт строку подключения и выполнит:
CREATE SUBSCRIPTION "migration"
CONNECTION 'dbname="app" host="<HOST>.rds.amazonaws.com" passfile="/controller/external/rds/pgpass" user="postgres"'
PUBLICATION migration;Пароль в БД не утекает — лежит в Kubernetes Secret, подкладывается через passfile.
Лаг репликации:
SELECT confirmed_flush_lsn, pg_current_wal_lsn(),
(pg_current_wal_lsn() - confirmed_flush_lsn) AS lsn_distance
FROM pg_replication_slots
WHERE slot_name = 'migration';Синхронизация sequences:
kubectl cnpg subscription sync-sequences \
--subscription migration \
angusCutover
Перед боевым переключением:
- Прорепетируйте cutover хотя бы один раз.
- Поднимите количество реплик до 3.
- Настройте физические бэкапы новой БД.
- Проверьте восстановление из бэкапа.
Сам cutover:
- Останавливаете запись из приложения.
- Дожидаетесь полной синхронизации подписки.
- Обновляете sequences.
- Проверяете целостность данных.
- Раскатываете новую версию приложения, которая ходит на сервис
angus-rw. - Удаляете подписку и публикацию.
Выводы
Подход работает с любым PostgreSQL 10+, доступным по сети и поддерживающим логическую репликацию: DBaaS, VM, bare metal, другой Kubernetes-оператор. Та же методика подходит и для major-апгрейдов. Особое внимание — на расширения PostgreSQL: их совместимость надо проверять отдельно.