Что такое Flink CDC
CDC — это Change Data Capture, технология чтения изменений из транзакционной БД (MySQL binlog, Postgres logical replication, MongoDB oplog) в виде потока событий. Долгое время de-facto-стандартом был Debezium + Kafka Connect: Debezium коннекторы запускаются как Kafka Connect tasks, читают binlog/WAL, публикуют в Kafka. Дальше — обычный Kafka consumer.
Flink CDC — это альтернативная архитектура: тот же самый Debezium engine, но embedded прямо в Flink source task. Никаких отдельных Kafka топиков для CDC, никакого Kafka Connect-кластера. В этом уроке разберём, как это устроено, чем отличается от классического подхода и когда что выбирать.
Классический CDC: Debezium + Kafka Connect
Канонический pipeline в индустрии 2017-2022:
Архитектура DebeziumMySQL -> Debezium connector (в Kafka Connect) -> Kafka topic -> Flink/Spark consumer
Debezium читает MySQL binlog (или Postgres WAL, MongoDB oplog), парсит, преобразует в события before/after JSON или Avro, публикует в Kafka топик dbserver1.inventory.orders. Любой downstream-consumer (Flink job, Spark, аналитика) подписывается на этот топик.
Преимущества:
- Reuse — один CDC source, много consumers. Каждая команда читает топик независимо.
- Buffering — Kafka работает буфером: если downstream упал, Kafka хранит события до его восстановления (зависит от retention).
- Standard tooling — Debezium UI, Confluent Connect API для управления, мониторинг через Kafka Connect REST.
Недостатки:
- Лишний компонент — Kafka Connect кластер надо deploy’ить, мониторить, патчить.
- Сериализация -> десериализация — события Debezium-сериализуется в Kafka, потом Flink десериализует. Это CPU и latency.
- Snapshot bottleneck — initial snapshot большой таблицы (миллиарды строк) делается одним Connect task. На таблице 1B rows — может занять дни.
- Координация schema — schema evolution Debezium и downstream-приложений не всегда совпадают.
Flink CDC: embedded approach
Flink CDC переворачивает архитектуру: Debezium engine внутри Flink source task. Нет Kafka Connect, нет промежуточного Kafka топика.
MySQL -> Flink source task (with embedded Debezium) -> Flink pipeline -> sink
CREATE TABLE orders_cdc (
order_id BIGINT,
customer_id BIGINT,
amount DECIMAL(10, 2),
status STRING,
updated_at TIMESTAMP(3),
PRIMARY KEY (order_id) NOT ENFORCED
) WITH (
'connector' = 'mysql-cdc',
'hostname' = 'mysql.internal',
'port' = '3306',
'username' = 'flink_cdc',
'password' = '...',
'database-name' = 'shop',
'table-name' = 'orders',
'server-id' = '5400-5404',
'scan.incremental.snapshot.enabled' = 'true'
);
'connector' = 'mysql-cdc' подключает Flink source, который содержит Debezium engine для MySQL. Этот source делает две фазы:
- Snapshot — читает существующие строки таблицы и emit их как
+Ievents. - Streaming — переключается на binlog reader, emit insert/update/delete события.
MySQL
MySQL primary с binlog enabled. Источник изменений для CDC.Debezium + Kafka Connect
Debezium connector внутри Kafka Connect worker. Читает binlog одним task, парсит events, публикует в Kafka.Kafka topic
Kafka topic dbserver1.shop.orders. Хранит CDC events. Любой consumer может subscribe.Flink consumer
Flink job consumer'ит CDC events из Kafka. Десериализует, применяет логику.MySQL
MySQL primary, тот же source.Flink CDC source
Flink source task с embedded Debezium engine. Параллельный snapshot (multi-task), потом switch на binlog. Нет Kafka в середине.Flink downstream
Flink pipeline — обычный downstream-operator (transform, join, sink). Изменения уже в Flink RowData формате.Параллельный snapshot
Главное архитектурное преимущество Flink CDC над классическим Debezium — параллельный snapshot (с версии 2.0).
Классический Debezium snapshot:
- Один Connect task делает
SELECT * FROM table(или с offset chunks). - На таблице 1B rows × 200 bytes = 200 GB —
SELECT *идёт часы или дни. - Если упал — начинает сначала (без incremental progress).
Flink CDC параллельный snapshot:
- Source разделяется на N source subtasks.
- Каждый subtask берёт chunk диапазона primary key (
SELECT * WHERE id BETWEEN ? AND ?). - Snapshot N chunks делается параллельно.
- При checkpoint state сохраняется per-chunk — incremental progress, recovery без full restart.
WITH (
'connector' = 'mysql-cdc',
...
'scan.incremental.snapshot.enabled' = 'true', -- параллельный snapshot
'scan.incremental.snapshot.chunk.size' = '8096', -- размер chunk (rows)
'chunk-key.even-distribution.factor.upper-bound' = '1000.0'
);
При parallelism=8 — 8 параллельных chunk readers. Snapshot 1B rows ускоряется в 8x.
Параллельный snapshot не только быстрее, но и resumable. При failure снапшота уже скачанные chunks не теряются — recovery начинается с unfinished chunks. На таблице 100M+ это огромное преимущество перед классическим Debezium, который начинал snapshot заново.
Exactly-once семантика
Flink CDC дает exactly-once для всего pipeline без двойной транзакции (которая нужна в Debezium+Kafka).
В классической схеме у вас две точки exactly-once:
- Debezium -> Kafka (через Debezium transaction metadata).
- Kafka -> Flink -> sink (через Flink checkpoint).
Между этими двумя — Kafka, и атомарность delivery не гарантируется (есть at-least-once случаи).
В Flink CDC:
- Source с embedded Debezium emit events напрямую в Flink pipeline.
- Flink checkpoint включает позицию binlog (gtid или log file + position).
- При recovery Flink восстанавливает binlog position из checkpoint и continue.
Один checkpoint покрывает source -> pipeline -> sink. End-to-end exactly-once без посредников.
Когда использовать что
Debezium + Kafka Connect, когда:
- Multiple consumers: один CDC source, 5 downstream-сервисов читают разными способами. Kafka буфер обязателен.
- Buffering против outage: downstream может падать на дни, Kafka хранит CDC events до восстановления.
- Существующий Kafka Connect deploy: уже работает, инфраструктура есть, добавить Debezium тривиально.
- Schema registry первого класса: Confluent stack даёт хорошую schema-evolution-pipeline.
Flink CDC, когда:
- Single consumer: один Flink job обрабатывает CDC. Зачем тогда промежуточный Kafka.
- Big snapshots: таблицы миллиарды rows, параллельный snapshot — ключевая фича.
- End-to-end exactly-once: важно атомарно перенести изменения из БД в downstream (Iceberg, Paimon, другая БД).
- Минимум инфраструктуры: не хочется поддерживать отдельный Kafka Connect кластер.
Поддерживаемые БД
В Flink CDC проекте (на 2026):
- MySQL — MySQL 5.6+, MariaDB. Параллельный snapshot.
- PostgreSQL — Postgres 10+. Через logical decoding (pgoutput или wal2json).
- MongoDB — через change streams (Mongo 4.0+, replica set required).
- Oracle — через LogMiner. Поддержка чуть менее зрелая.
- SQL Server — через CDC tables.
- TiDB — через TiCDC.
- OceanBase, PolarDB-X — китайские БД, активно поддерживаются.
- DB2 — через DB2 transaction log.
Все коннекторы используют один и тот же Debezium engine под капотом, разница — в подключении к binlog/WAL/oplog конкретной БД.
Flink CDC как pipeline framework
Помимо source-коннекторов, Flink CDC проект (с версии 3.0) включает CDC pipeline framework — декларативный YAML-формат для CDC-pipelines:
source:
type: mysql
hostname: mysql.internal
port: 3306
username: flink_cdc
password: ...
tables: shop.orders, shop.products
server-id: 5400-5404
sink:
type: paimon
catalog.warehouse: s3://lake/paimon/
catalog.metastore: hive
pipeline:
name: shop-cdc-to-paimon
parallelism: 4
Запускается через bin/flink-cdc.sh shop-pipeline.yaml. Это полностью декларативный pipeline без Java/Scala кода. Подробнее в следующих уроках.
Попробуй сам
- Сравни время snapshot 100M rows таблицы Debezium-классиком vs Flink CDC с parallelism=8. Что повлияет на разницу?
- Подумай, можно ли использовать Flink CDC, если несколько downstream-сервисов хотят читать CDC. Какие компромиссы?
- Что произойдёт, если Flink CDC job упадёт во время snapshot фазы? А во время binlog фазы?