Change Data Capture

Потоковая передача построчных изменений из базы данных. Источник CDC захватывает вставки, обновления и удаления, при необходимости сначала передаёт каждому подписчику согласованный снимок существующих строк и доставляет всё в виде нейтральных к драйверу событий изменений. Источники адресуются по ID своей записи и потребляются из Lua через модуль cdc.

Типы записей

Вид Описание
db.cdc.postgres Логическая репликация Postgres (плагин pgoutput)
db.cdc.sqlite Записи SQLite, наблюдаемые через ресурс db.sql.sqlite

Оба вида предоставляют один и тот же Lua API, одну и ту же запись с информацией об источнике и одну и ту же форму события изменения. Различается набор гарантий, публикуемый для каждого источника в виде возможностей.

Конфигурация Postgres

- name: pg_cdc
  kind: db.cdc.postgres
  host: ${env:DB_HOST}
  port: 5432
  database: app
  username: ${env:DB_USER}
  password: ${env:app.secrets:db_password}
  slot_name: wippy_slot
  publication: wippy_pub
  tables:
    - public.users
    - public.orders
  snapshot: true
  streaming: true
  standby_interval: "10s"
  status_interval: "10s"
  lifecycle:
    auto_start: true
Поле Тип По умолчанию Описание
host string обязательно Хост Postgres
port int обязательно Порт Postgres (должен быть > 0)
database string обязательно Имя базы данных
username string обязательно Пользователь репликации (должен иметь привилегию REPLICATION)
password string обязательно Пароль (напрямую или ${env:NAME})
slot_name string обязательно Имя слота логической репликации
publication string - Публикация Postgres; обязательна, когда tables пуст
tables []string - Захватываемые таблицы (schema.table); опустите, чтобы использовать таблицы публикации
snapshot bool false Значение по умолчанию на уровне записи для передачи снимка каждому подписчику
streaming bool false Использовать потоковую версию протокола pgoutput
temporary bool false Использовать временный слот репликации (удаляется при отключении)
failover bool false Включить режим слота отказоустойчивости (взаимоисключающий с temporary)
standby_interval duration 10s Интервал сообщений о статусе резервного узла (например, 10s)
status_interval duration 30s Интервал обновления статуса на сервере
snapshot_fetch_size int 1000 Число строк, выбираемых за пакет снимка (должно быть >= 0)
max_transaction_changes int 1000000 Максимум изменений в буфере при декодировании одной транзакции
max_transaction_bytes int 268435456 Максимум логических байт в буфере при декодировании одной транзакции (256 МиБ)
max_inflight_changes int 1000000 Максимум изменений, удерживаемых по всем транзакциям в обработке
max_inflight_bytes int 268435456 Максимум логических байт, удерживаемых по всем транзакциям в обработке (256 МиБ)
subscriptions object - Лимиты допуска подписок, см. Лимиты подписок
options map - Дополнительные опции подключения
lifecycle object - Конфигурация жизненного цикла

Ноль в любом поле max_* выбирает значение по умолчанию; декодер никогда не работает без ограничений. Отрицательные значения отклоняются.

Учётные данные разрешают плейсхолдеры ${env:NAME} через реестр окружения во время декодирования.

Конфигурация SQLite

Источник SQLite не открывает собственную базу данных. Он заимствует существующий ресурс db.sql.sqlite и подписывается на наблюдателя зафиксированных мутаций этого ресурса, поэтому захватывает ровно те записи, которые сделаны через этот SQL-ресурс Wippy — записи другого процесса, другого соединения или внешнего инструмента не наблюдаются.

- name: cdcdb
  kind: db.sql.sqlite
  file: /var/data/app.db
  lifecycle:
    auto_start: true

- name: changes
  kind: db.cdc.sqlite
  db_resource: app:cdcdb
  tables:
    - users
    - orders
  snapshot: true
  status_interval: "30s"
  lifecycle:
    auto_start: true
Поле Тип По умолчанию Описание
db_resource string обязательно ID записи ресурса db.sql.sqlite, за которым ведётся наблюдение
name string - Принимается; имя источника всегда равно ID записи
tables []string - Захватываемые таблицы; опустите для всех таблиц
snapshot bool false Значение по умолчанию на уровне записи для передачи снимка каждому подписчику
status_interval duration 30s Интервал обновления статуса
subscriptions object - Лимиты допуска подписок, см. Лимиты подписок
lifecycle object - Конфигурация жизненного цикла

Источник объявляет SQL-ресурс требованием жизненного цикла, поэтому супервизор сначала запускает базу данных и перезапускает источник, когда поколение базы данных заменяется.

Захват SQLite требует сборки среды выполнения с тегом сборки sqlite_preupdate_hook. Официальные сборки его включают. Без этого тега драйвер отказывает: создание записи db.cdc.sqlite возвращает sqlite cdc requires the sqlite_preupdate_hook build tag вместо запуска источника, который ничего не захватывает.

Лимиты подписок

Каждый источник допускает ограниченное число подписчиков и резервирует их очередь по худшему случаю заранее. Слот снимка остаётся зарезервированным, пока поток со снимком не закроется.

subscriptions:
  max_subscriptions: 1024
  max_snapshot_subscriptions: 4
  max_bytes: 268435456
Поле Тип По умолчанию Описание
max_subscriptions int 1024 Одновременные подписки, допускаемые источником
max_snapshot_subscriptions int 4 Одновременные подписки со снимком
max_bytes int 268435456 Общий объём зарезервированных байт очередей подписчиков (256 МиБ)

Ноль выбирает значение по умолчанию; отрицательные значения отклоняются. Исчерпание лимита завершает подписку повторяемой ошибкой errors.UNAVAILABLE.

Как это работает

  1. Источник Postgres подключается как пользователь репликации и создаёт (или возобновляет) слот с именем из slot_name. Источник SQLite заимствует свой db_resource и подписывается на наблюдателя зафиксированных мутаций этого ресурса.
  2. Изменения строк декодируются в нейтральные к драйверу события изменений с op, равным insert, update, delete или truncate.
  3. Подписчик, у которого в потоке включён snapshot — из поля snapshot записи или из opts.snapshot в потоке — сначала получает существующие строки как события с op = "snapshot", затем продолжает живыми изменениями без разрыва между ними.
  4. Источник Postgres периодически подтверждает LSN, чтобы сервер мог освобождать сегменты WAL (standby_interval).
  5. Источник регистрируется под ID своей записи; код на Lua подписывается через cdc.stream.

Возможности

Каждый источник публикует то, что он гарантирует, поэтому потребители ветвятся по возможностям, а не по виду записи.

Возможность db.cdc.postgres db.cdc.sqlite Значение
snapshot да да Поддерживает атомарную передачу снимка с переходом в живой режим
capture_resume да, кроме temporary нет Прогресс источника переживает переподключение
replayable нет нет Отдельные подписчики могут воспроизвести прошедшие события
captures_external_writes да нет Захватывает записи, сделанные вне этой среды выполнения
before_images нет да Гарантирует полный образ строки до изменения при update и delete
coalesced нет да Повторные записи в строку внутри транзакции могут приходить объединёнными

Флаги возможностей описывают прогресс источника, а не надёжную доставку: ни один драйвер не воспроизводит события для отдельного подписчика, который отстал или отключился.

Информация об источнике

Каждый источник описывается записью информации, которую возвращают cdc.source и cdc.list_sources.

Поле Тип Описание
id string ID записи
kind string db.cdc.postgres или db.cdc.sqlite
name string Имя источника (ID записи)
state string unknown, starting, running, faulted или stopped
generation string Текущее поколение источника; меняется при замене источника
epoch string То же значение, что и generation
engine string Имя движка (sqlite)
db_resource string ID записи наблюдаемого SQL-ресурса (db.cdc.sqlite)
slot string Имя слота репликации (db.cdc.postgres)
publication string Публикация Postgres, когда настроена
tables []string Захватываемые таблицы, когда настроены
streaming bool Работает ли источник в данный момент
failover bool Режим слота отказоустойчивости (db.cdc.postgres)
temporary bool Временный слот (db.cdc.postgres)
snapshot bool Значение снимка по умолчанию на уровне записи
faulted bool Находится ли источник в состоянии faulted
error string Последняя ошибка источника, если она записана
admission object active, snapshots, reserved_bytes, rejected
capabilities object См. Возможности

admission считает резервирования, а не заполнение очереди: active — число допущенных подписок, snapshots — подмножество со снимком, reserved_bytes — зарезервированный бюджет очередей, а rejected — суммарное число подписок, отклонённых лимитами.

Разрешения

Действие Ресурс Описание
cdc.source ID записи источника Чтение информации об источнике; также фильтрует cdc.list_sources
cdc.subscribe ID записи источника Открытие потока изменений

Полномочия CDC отделены от доступа к базе данных: источник может раскрыть каждую захваченную строку, включая образы до изменения. Фильтры потока лишь сужают доставку; они никогда не дают доступ к источнику.

- name: cdc_reader
  kind: security.policy
  policy:
    effect: allow
    actions: [cdc.source, cdc.subscribe]
    resources: [app:changes]

См. также

  • Модуль CDC - Потоковый Lua API
  • Database - Сервисы SQL-баз данных
  • Environment - Разрешение учётных данных через ${env:NAME}
  • Security - Политики и действия