CDC и Debezium на собеседовании Data Engineer
Карьерник — Duolingo для аналитиков: 10 минут в день тренируй SQL, Python, A/B, статистику, метрики и ещё 3 темы собеса. 1500+ вопросов в Telegram-боте. Бесплатно.
Содержание:
Зачем CDC
Change Data Capture — поток изменений из OLTP-БД в DWH в реальном времени. Альтернатива — ночные batch-выгрузки полной таблицы. На больших таблицах batch занимает часы, нагружает прод, теряет промежуточные изменения (Customer status: new → active → cancelled за 5 минут — batch увидит только cancelled).
Главная боль без CDC — отчёты опаздывают на сутки, поведение «шёл-шёл и передумал» не виден в DWH. С CDC данные в DWH — почти онлайн, но возникают новые грабли: ordering, дубли, schema changes.
На собесе DE спрашивают: «Что такое CDC?», «Чем log-based отличается от query-based?», «Как работает Debezium?». Это middle+-уровень, junior часто плывёт.
Query-based CDC
Самый простой подход — SELECT по updated_at:
SELECT * FROM orders WHERE updated_at > :last_runПлюсы:
- Не требует доступа к replication log БД
- Работает на любой БД с timestamp-колонкой
Минусы:
- DELETE незаметен. Удалённая строка просто исчезает из выборки.
- Hard updates без изменения
updated_atтеряются. - Нагружает БД полным scan по индексу
- Не ловит промежуточные значения (между запусками строка могла поменяться 5 раз)
- Late writes: данные с
updated_at < last_runпишутся позже — пропустим
Когда применять: dimensions, которые меняются редко, без DELETE; маленькие таблицы; нет доступа к replication log.
Log-based CDC и Debezium
Log-based CDC — читать журнал изменений БД:
- Postgres: WAL через
wal2jsonилиpgoutput(logical replication) - MySQL: binlog
- Oracle: LogMiner / GoldenGate
- MS SQL: SQL Server CDC / change tracking
- MongoDB: oplog
Debezium — open-source CDC платформа поверх Kafka Connect. Подключается к БД, читает log, публикует события в Kafka.
[Postgres WAL] → Debezium PG connector → Kafka topic "orders" → consumers (DWH, search, cache)Формат события Debezium (упрощённо):
{
"op": "u",
"before": {"id": 1, "amount": 100, "status": "new"},
"after": {"id": 1, "amount": 100, "status": "paid"},
"source": {"ts_ms": 1730000000, "lsn": "0/16B6378"},
"ts_ms": 1730000001
}op: c create, u update, r snapshot read, d delete.
Плюсы log-based:
- DELETE регистрируется
- Не нагружает БД (читаем log, не таблицы)
- Все промежуточные состояния
- Минимальная задержка (миллисекунды)
Минусы:
- Сложнее настройка (replication slot, права в БД)
- Schema changes требуют отдельной обработки
- Replication slot в Postgres лочит WAL — если consumer отстаёт, диск заполняется
Snapshot и стриминг
При первом запуске Debezium делает initial snapshot — читает таблицу полностью, эмитит события op=r. После этого переключается на чтение log.
T1: snapshot всех 10М строк → эмитит 10М `op=r` событий
T2: подключается к log с момента T0
T3: пишет реальные изменения (`c`/`u`/`d`)Snapshot-стратегии:
initial— снимок один раз при первом запуске (дефолт)never— без снимка, только новые измененияinitial_only— снимок и завершитьwhen_needed— снимок только при потере позиции в log
Грабля: во время snapshot БД лочится (на innodb-lock или snapshot-isolation). На больших таблицах — часами. Решения: incremental snapshot (Debezium 1.6+) — снимок без лока, по чанкам.
Доставка в DWH
CDC-события из Kafka → DWH. Два паттерна:
Append-only / event log в DWH:
fact_orders_changelog:
| ts_ms | op | order_id | amount | status |
| 1000 | c | 1 | 100 | new |
| 2000 | u | 1 | 100 | paid |
| 3000 | d | 1 | NULL | NULL |Финальное состояние получаем через окно argMax или LAST_VALUE OVER (PARTITION BY order_id ORDER BY ts_ms).
Materialized current state в DWH:
fact_orders: (текущее состояние)
| order_id | amount | status |Поддерживается через MERGE/UPSERT по событиям. Дороже на write, дешевле на read.
В ClickHouse — ReplacingMergeTree с версионной колонкой и регулярным OPTIMIZE FINAL. В Iceberg/Delta — MERGE INTO.
Дедупликация: Kafka гарантирует at-least-once, дубли возможны. Дедуплицировать по (source.lsn/source.ts_ms/event_id).
Schema changes
ALTER TABLE в OLTP — отдельная история CDC.
- Add column: безопасно, новый column в новых событиях
- Drop column: последующие события без колонки — DWH должен принять как NULL
- Rename column: разрыв совместимости, обработать вручную
- Type change: тяжёлый случай, обычно — миграция
Debezium публикует schema change topic с DDL-операциями. DWH-сторона должна слушать и эволюционировать схему.
В Iceberg/Delta schema evolution встроена. В Parquet+Glue — через Glue Catalog.
Частые ошибки
Query-based CDC без soft-delete. DELETE в OLTP не виден. Решение: либо soft-delete (deleted_at), либо log-based.
Не мониторить replication slot lag. Debezium не успевает читать → Postgres держит WAL → диск кончается → авария.
Игнорировать ordering. В Kafka сообщения в одной партиции упорядочены. Если ключ partition = id, события одного id идут в порядке. Если ключ другой — порядок не гарантирован.
Снапшот без incremental на 1ТБ-таблице. Часовой down БД. Использовать incremental snapshot.
Нет idempotency у consumer. Дубли из Kafka попадают в DWH. UPSERT по бизнес-ключу или дедуп по offset.
Не обработать tombstone. Debezium DELETE — событие с op=d, after=null + tombstone (null payload) для compaction. Consumer должен корректно обработать оба.
Без backfill через Debezium для исторических данных. Snapshot захватит текущее состояние, но история изменений до Debezium — потеряна. Если нужна история — параллельно догружать из dump'ов.
Связанные темы
- Kafka на собеседовании DE
- Идемпотентность пайплайна для DE
- Подготовка к собесу Data Engineer
- SCD типы для DE
- dbt на собесе DE
FAQ
Debezium или Kafka Connect JDBC source — что выбрать?
JDBC source — query-based, прост, но без DELETE и снимков. Debezium — log-based, сложнее настроить, но мощнее. Для прод-критичных пайплайнов — Debezium.
Можно ли без Kafka запустить CDC?
Можно: Debezium Server / Debezium Embedded Engine (без Kafka Connect). Но Kafka даёт buffer, replay, fan-out — для прод обычно используют с Kafka.
Что такое exactly-once в Debezium?
Debezium гарантирует at-least-once через Kafka. Exactly-once в DWH — забота consumer-стороны (idempotent UPSERT по primary key).
CDC заменяет ETL?
Не полностью. CDC даёт изменения, ETL/ELT — трансформации. Современный паттерн: CDC → raw layer (bronze) → dbt трансформирует в silver/gold.
Debezium работает с Postgres replicas?
Да, через physical replication, но логическая (WAL) предпочтительнее. С Postgres ≥ 10 — pgoutput / wal2json плагины.
Это официальная информация?
Нет. Статья основана на документации Debezium, Postgres logical replication, Kafka Connect. Конкретные настройки зависят от версий и стека компании.
Тренируйте Data Engineering — откройте тренажёр с 1500+ вопросами для собесов.