Debezium、Kafka Connect 与 Flink CDC 实时同步生产实战
CDC(Change Data Capture)通过数据库日志捕获增删改,为缓存、搜索、数仓、事件驱动和跨库同步提供低侵入数据通道。生产 CDC 的难点不只是“能看到 Binlog”,还包括快照与增量衔接、位点、顺序、重复、Schema 变化、删除语义、重平衡、下游幂等、延迟和灾难恢复。本文覆盖 Debezium/Kafka Connect 与 Flink CDC 的主要运维方法。
CDC 事件可能包含个人信息、密码摘要、Token、订单和财务数据。上线前必须进行字段分级、最小权限、传输加密、Topic ACL、日志脱敏和保留策略设计。
一、先定义同步语义
需求必须回答:
- 全量 + 增量,还是只从当前时刻捕获;
- 是否允许秒级延迟;
- 是否允许重复,如何去重;
- 是否要求同一主键有序,是否要求跨表事务顺序;
- 删除在下游表现为物理删除、软删除还是 Tombstone;
- DDL 如何同步;
- 下游不可用时可积压多久;
- 源库日志能保留多久;
- RPO、RTO 和重建成本。
“Exactly Once”不能只看一个组件的宣传。端到端恰好一次要求 Source 可回退到 Checkpoint,处理状态一致,Sink 能事务提交或幂等写入。
二、典型架构
MySQL/PostgreSQL/Oracle/SQL Server
↓ 数据库日志
Debezium Connector / Flink CDC Source
↓
Kafka Topic 或 Flink Pipeline
↓
Sink Connector / Flink Sink / 自定义消费者
↓
Elasticsearch、Doris、ClickHouse、数据湖、缓存
Debezium 常运行在 Kafka Connect 中,将变更事件写入 Kafka;Flink CDC 可直接构建端到端 Pipeline,也可将 CDC 事件写入 Kafka。两者可以组合,但应避免不必要的重复链路。
三、源数据库准备
MySQL
需配置 Row 格式 Binlog、唯一 Server ID、足够的日志保留和专用最小权限账号。大事务和无主键表会影响快照与下游处理。
SHOW VARIABLES LIKE 'log_bin';
SHOW VARIABLES LIKE 'binlog_format';
SHOW BINARY LOG STATUS;
SHOW BINARY LOGS;
PostgreSQL
逻辑复制依赖 wal_level=logical、Replication Slot 和 Publication。Slot 会阻止仍需的 WAL 被回收,Connector 长期停止可能撑满磁盘。
SELECT slot_name, active, restart_lsn, confirmed_flush_lsn
FROM pg_replication_slots;
Oracle 与 SQL Server
分别关注归档日志/补充日志/LogMiner 或 XStream,以及 SQL Server CDC/Agent、日志截断和权限。具体能力与授权边界必须按所用版本官方文档核对。
四、初始快照
初始快照读取历史数据,再切换到日志增量。风险包括:
- 大表扫描影响 Buffer Cache 和磁盘;
- 长事务或锁;
- 快照持续时间超过日志保留;
- 并发 DDL 导致 Schema 不一致;
- 网络或 Connector 重启造成重扫;
- 下游突然接收海量历史数据。
上线前压测快照吞吐,控制并发、Fetch Size 和分片范围,并为源端与下游预留容量。增量快照可按块补采部分表,但仍需验证所用连接器的边界。
五、事件结构与主键
Debezium 事件通常包含 before、after、op、source 和时间等信息。消费者不应只读取 after 而忽略操作类型。
{
"before": {"id": 42, "status": "new"},
"after": {"id": 42, "status": "paid"},
"op": "u",
"source": {"table": "orders"}
}
无主键表难以稳定分区、更新和去重。生产应尽量补充主键;无法补充时,要明确使用哪些字段生成 Key,以及重复行和字段变更的处理方式。
六、Kafka Topic 设计
Topic 数量、分区数和保留时间需要同时满足吞吐、顺序和恢复窗口。
- 同一 Key 放入同一分区,可保持分区内顺序;
- 增加分区会改变 Key 到分区的映射,消费者状态需谨慎处理;
- 日志保留必须覆盖最长下游中断和重放需求;
- 压缩 Topic 可保留 Key 的最新值,但删除 Tombstone 和清理时机要理解;
- Schema History Topic 与普通业务 Topic 权限、保留策略不同。
不要让 Schema History Topic 被短保留策略清空,否则 Connector 重建时可能无法正确解释历史 Schema。
七、Offset 与恢复
Offset 记录源日志位点。Kafka Connect 通常存于内部 Topic,Debezium Server/Engine 或其他部署方式有各自存储。备份范围必须包含:
- Connector 配置;
- Offset;
- Schema History;
- Topic 配置和 ACL;
- 转换 SMT;
- 密钥和证书。
错误重置 Offset 可能导致重复重放或跳过数据。任何位点调整都应先保存原值,并在隔离环境验证。
八、Kafka Connect 集群
Distributed 模式下多个 Worker 共享 Group。配置 Topic、Offset Topic 和 Status Topic 必须具有合适分区、复制因子和清理策略。
curl -s http://connect:8083/connectors
curl -s http://connect:8083/connectors/orders-cdc/status
curl -s http://connect:8083/connectors/orders-cdc/tasks/0/status
重平衡期间 Task 可能暂停。频繁扩缩容、Worker 网络抖动、插件版本不一致和长时间停止任务都会造成不稳定。
九、SMT 的使用边界
Single Message Transform 适合轻量字段路由、重命名、过滤和格式调整。不适合复杂 JOIN、大状态聚合或外部远程调用。
变换前考虑:
- 是否丢失
before/source/op导致无法追溯; - 删除事件是否被误过滤;
- 字段改名与下游 Schema 兼容;
- 敏感字段是在源侧、Connect 还是 Sink 脱敏;
- 失败事件如何进入 DLQ。
十、Flink CDC Pipeline
Flink CDC 可用 YAML 描述 Source、Transform、Route、Sink 和 Pipeline。生产需配置 Checkpoint 到持久存储,并理解 Sink 的提交语义。
source:
type: mysql
hostname: db.example.internal
port: 3306
username: cdc_reader
password: ${CDC_PASSWORD}
tables: app_db.orders
server-id: 5400-5404
sink:
type: kafka
properties.bootstrap.servers: kafka:9092
topic: orders_cdc
value.format: debezium-json
pipeline:
name: orders-cdc
parallelism: 2
示例中的密码应由密钥系统注入,不应提交到仓库。
十一、Checkpoint、Savepoint 与 Exactly Once
Checkpoint 是自动故障恢复状态,Savepoint 更偏向计划升级和迁移。生产 Checkpoint 应保存到持久分布式存储,监控耗时、失败和大小。
端到端 Exactly Once 还取决于:
- Source 位点可回退;
- Checkpoint 成功后状态一致;
- Sink 支持事务或幂等;
- 外部副作用纳入提交协议;
- 故障恢复不会绕过旧事务清理。
即便系统语义是 Exactly Once,业务下游仍建议按主键与版本/位点实现幂等。
十二、Schema 演进
上游 DDL 可能新增、删除、重命名字段或改变类型。Flink CDC 支持多种 Schema Change 行为,例如严格失败、尝试演进、宽松或忽略。选择依据是下游能力和数据安全。
生产建议:
- 新增 Nullable 字段优先;
- 类型缩小、字段删除和改名需评审;
- DDL 先在测试链路验证;
- 记录上游/下游 Schema 版本;
- 失败时暂停,不要静默丢字段;
- 对不支持的 Sink 明确人工变更流程。
“自动同步 DDL”不是越自动越好,错误 Drop 可能传到分析库造成二次事故。
十三、删除与 Tombstone
数据库 Delete 事件可能产生带 before 的删除记录和后续 Tombstone。Sink 需要明确:
- 删除目标行;
- 标记
is_deleted; - 保留审计历史;
- 忽略删除。
如果下游只做 Upsert 而忽略删除,数据会长期不一致。反之,错误匹配 Delete Key 可能删除不相关记录。
十四、延迟排查
把端到端延迟拆成:
源库日志产生
→ Connector 读取
→ Kafka 入队
→ 消费与处理
→ Sink 写入
→ 下游可查询
分别观察源端日志积压、Connector Source 时间戳、Kafka Consumer Lag、Flink Backpressure、Checkpoint、Sink 批量与错误。只看 Kafka Lag 为 0,不能证明下游已经可查询。
十五、背压与下游故障
下游慢时,Flink 会出现 Backpressure,Kafka Consumer Lag 增长,最终可能超过源日志或 Topic 保留窗口。处置:
- 保护数据,暂停无关作业;
- 确认下游容量、限流和错误;
- 调整批量、并发和重试;
- 防止无限重试阻塞所有分区;
- 对坏数据使用受控 DLQ;
- 恢复后限制追赶速率,避免冲垮下游。
十六、数据校验与对账
实时链路必须有持续对账。方法包括:
- 分区/时间窗口行数;
- 主键抽样;
- 业务金额、状态等聚合;
- 哈希分桶;
- 延迟水位;
- Delete/Update 数量;
- Schema 一致性。
发现差异后,应能按表、主键区间或时间窗口重新同步,而不是只能全量重建。
十七、监控告警
监控 Connector/Task 状态、快照进度、源位点、日志保留窗口、Kafka Lag、DLQ、重试、Schema History、Flink Checkpoint、Backpressure、重启次数、Sink 错误、端到端延迟和对账差异。
告警要附带表、分区、位点、错误样本和恢复入口,但必须对敏感字段脱敏。
十八、上线清单
- 源库日志、权限和保留窗口满足要求;
- 表有稳定主键或明确替代策略;
- 快照对源库和下游的压力已压测;
- Offset、Schema History、Checkpoint 可恢复;
- Delete、DDL、重复、乱序语义已测试;
- 下游实现幂等或事务提交;
- 具备 DLQ、重放和局部补数能力;
- 端到端对账和延迟告警已启用;
- 从故障位点恢复与全量重建均完成演练。
参考资料
- Debezium Documentation:
https://debezium.io/documentation/ - Apache Kafka Connect:
https://kafka.apache.org/documentation/#connect - Apache Flink CDC:
https://nightlies.apache.org/flink/flink-cdc-docs-stable/ - Flink Checkpointing:
https://nightlies.apache.org/flink/flink-docs-stable/docs/dev/datastream/fault-tolerance/checkpointing/