Change Data Capture (CDC) и Debezium: как стримить изменения
Продвинутое3 минРедакция Innovialabs
Коротко
CDC на основе журнала читает журнал транзакций базы и превращает каждую вставку, изменение и удаление в событие; Debezium делает это для PostgreSQL, MySQL и других СУБД и публикует события в Kafka, поэтому хранилище, поисковый индекс и кеш синхронизируются за секунды, а не после следующего пакетного запуска.
Коротко
Change Data Capture (CDC) — захват каждого изменения в базе и доставка его в другие системы. Самый надёжный вариант — CDC на основе журнала: вместо запросов к таблицам он читает журнал транзакций самой базы, тот же, что используется для репликации.
Debezium — open-source платформа для CDC. Она подключается к журналу, превращает каждое изменение строки в событие и обычно публикует его в Apache Kafka, откуда его может читать любое число потребителей.
Три способа захватывать изменения
| Подход | Как работает | Слабые места |
|---|---|---|
| Запросы | Опрос WHERE updated_at > last_run | Не видит физических удалений, зависит от надёжного timestamp, нагружает базу |
| Триггеры | Триггеры пишут изменения в таблицу аудита | Лишняя запись в каждой транзакции, триггеры надо поддерживать |
| Журнал | Чтение WAL (PostgreSQL) или binlog (MySQL) | Нужен доступ к журналу и настройка, больше компонентов |
CDC на основе журнала видит каждое закоммиченное изменение, включая удаления, в порядке коммитов и почти не добавляет нагрузки на сами таблицы.
Как работает Debezium
Чаще всего Debezium запускается как source-коннектор в Kafka Connect. Для каждой базы он:
- Делает необязательный начальный снимок выбранных таблиц.
- Переходит к потоковому чтению журнала: в PostgreSQL через слот логической репликации (плагин
pgoutput), в MySQL через binlog в формате ROW. - Пишет события в топики Kafka, обычно по топику на таблицу с именем вида
prefix.schema.table. - Сохраняет позицию (offset), чтобы продолжить после перезапуска.
Каждое событие содержит состояние строки до и после изменения, тип операции (c создание, u изменение, d удаление, r чтение снимка) и метаданные источника — транзакцию и время.
Подготовка PostgreSQL:
# postgresql.conf
wal_level = logical
Минимальная регистрация коннектора в Kafka Connect:
{
"name": "shop-connector",
"config": {
"connector.class": "io.debezium.connector.postgresql.PostgresConnector",
"plugin.name": "pgoutput",
"database.hostname": "db",
"database.port": "5432",
"database.user": "debezium",
"database.password": "${file:/secrets/db.properties:password}",
"database.dbname": "shop",
"topic.prefix": "shop",
"table.include.list": "public.orders,public.customers"
}
}
Заведите для Debezium отдельного пользователя только с нужными правами на репликацию и чтение.
Доставка изменений дальше
Когда события в Kafka, их независимо могут использовать разные потребители:
- Хранилище данных (ClickHouse, BigQuery, Snowflake и другие) — через sink-коннекторы или потоковую обработку.
- Поисковый индекс, например Elasticsearch, — обновляется сразу после изменения товара.
- Инвалидация кеша в Redis.
- Другие микросервисы, которые реагируют на бизнес-события.
Если Kafka не нужна, Debezium Server умеет отправлять события напрямую в другие брокеры сообщений, а для JVM-приложений есть встраиваемый движок.
CDC против пакетного ETL для синхронизации хранилища
| Пакетный ETL | CDC на основе журнала | |
|---|---|---|
| Свежесть | После следующего запуска | Почти в реальном времени |
| Удаления | Часто теряются | Фиксируются |
| Нагрузка на источник | Тяжёлые запросы во время запуска | Чтение журнала |
| Сложность | Низкая: планировщик и SQL | Выше: Kafka, коннекторы, мониторинг |
| История изменений | Только итоговое состояние | Каждое промежуточное изменение |
Пакетный ETL по-прежнему хороший выбор, если достаточно свежести раз в день или раз в час, объём данных умеренный и в команде нет потоковой инфраструктуры. CDC окупается, когда отчёты должны быть свежими, таблицы большие или одни и те же изменения нужны нескольким системам.
Подводные камни
- Слоты репликации удерживают WAL. Если коннектор остановился, PostgreSQL хранит WAL для слота, и диск может переполниться. Следите за отставанием слота и настройте алерты.
- Доставка at-least-once. После сбоев события могут повторяться. Делайте потребителей идемпотентными, например upsert по первичному ключу.
- Изменения схемы должны обрабатывать потребители; рассмотрите schema registry.
- Порядок гарантирован в пределах ключа (партиции Kafka), а не глобально.
- Внутренние таблицы раскрывают структуру. Для событий, предназначенных другим сервисам, паттерн outbox (отдельная таблица событий, которую захватывает CDC) даёт стабильный контракт.