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_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.
Как это работает
- Источник Postgres подключается как пользователь репликации и создаёт (или возобновляет) слот с именем из
slot_name. Источник SQLite заимствует свойdb_resourceи подписывается на наблюдателя зафиксированных мутаций этого ресурса. - Изменения строк декодируются в нейтральные к драйверу события изменений с
op, равнымinsert,update,deleteилиtruncate. - Подписчик, у которого в потоке включён
snapshot— из поляsnapshotзаписи или изopts.snapshotв потоке — сначала получает существующие строки как события сop = "snapshot", затем продолжает живыми изменениями без разрыва между ними. - Источник Postgres периодически подтверждает LSN, чтобы сервер мог освобождать сегменты WAL (
standby_interval). - Источник регистрируется под 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 - Политики и действия