CDC 技术选型:三种主流方案深度对比

做 CDC 增量同步,第一步就是选技术方案。选错了,后面全白干。

市面上主流的 CDC 实现方式,说白了就三种:基于日志、基于轮询、基于触发器。每种都有各自的脾气秉性。我这些年踩过的坑,大部分都跟选型有关。今天咱们就把这三兄弟拉出来,好好盘一盘。

核心观点:没有银弹。选型不是选「最好的」,而是选「最适合你业务场景的」。日志型适合高并发、低延迟;轮询型适合数据量小、对延迟不敏感;触发器型……嗯,我建议你尽量别碰。

一、基于日志的 CDC(Debezium / Canal)

这是目前最主流、也是我个人最推荐的方式。它的原理很简单:数据库的每一次增删改,都会写入事务日志(比如 MySQL 的 binlog、PostgreSQL 的 WAL)。CDC 工具直接读取这些日志,解析成事件流,然后推送给下游。

Debezium 和 Canal 是这派的代表。Debezium 基于 Kafka Connect 生态,支持 MySQL、PostgreSQL、MongoDB 等;Canal 是阿里开源的,主要针对 MySQL。

优点

  • 对业务无侵入:不需要改表结构,不需要加字段,不需要写触发器代码。你想想看,这对 DBA 来说有多友好。
  • 延迟极低:日志是实时写入的,CDC 工具几乎是秒级捕获。我做过压测,Debezium 端到端延迟通常在 100ms 以内。
  • 不丢数据:日志是数据库持久化的一部分,只要日志没被清理,就能回溯。我曾经用 Debezium 做过一次全量+增量迁移,几亿条数据一条没丢。
  • 支持历史数据回溯:你可以从任意时间点开始消费,只要 binlog 还在。

缺点

  • 运维成本高:需要维护 Kafka 集群、Connector 状态、Schema Registry。小团队可能吃不消。
  • 对数据库有额外压力:日志读取会增加 I/O,尤其是大事务时。我记得有一次线上 binlog 暴增,直接把磁盘打满了……嗯,监控一定要做好。
  • 版本兼容性敏感:MySQL 8.0 和 5.7 的 binlog 格式有差异,Debezium 版本没跟上就会报错。

我的建议:如果你的业务对数据一致性要求高、延迟敏感、团队有 Kafka 运维能力,闭眼选日志型。Debezium 是首选,Canal 适合纯 MySQL 场景且不想引入 Kafka 的团队。

二、基于轮询的 CDC

轮询型 CDC,说白了就是「定时查表」。你在业务表上加一个 update_time 或自增 id,然后写个定时任务,每隔几秒或几分钟去扫一次表,把新增或变更的数据拉出来。

这种方式实现起来最简单,很多「数据同步工具」底层就是干这个的。

优点

  • 实现简单:写个 SQL 就能搞定,不需要额外组件。小团队、小项目上手极快。
  • 对数据库友好:没有日志解析的压力,只是普通的 SELECT 查询。
  • 兼容性好:任何数据库都支持,不挑版本。

缺点

  • 延迟高:轮询间隔决定了延迟。你设 5 秒,延迟就是 5 秒;设 1 分钟,延迟就是 1 分钟。做不到实时。
  • 对数据库压力大:频繁的 SELECT * WHERE update_time > ? 会全表扫描,数据量大了以后,数据库直接扛不住。我曾经见过一个项目,轮询间隔 10 秒,结果业务表 5000 万行,每次查询都要 30 秒……这哪是同步,这是 DDoS。
  • 无法捕获删除:物理删除的数据,轮询是查不到的。除非你改成逻辑删除(加 is_deleted 字段)。
  • 数据一致性难保证:如果更新发生在两次轮询之间,可能会漏掉。

避坑指南:我曾经接手过一个项目,用轮询同步订单数据。上线半年后,业务量翻了 10 倍,轮询查询直接把主库 CPU 打满,导致线上订单超时。最后紧急切成了 Debezium。如果你预估数据量会增长,一开始就别用轮询。

三、基于触发器的 CDC

触发器型 CDC,就是在数据库表上建 INSERT、UPDATE、DELETE 触发器,把变更记录写到一张专门的日志表里,然后另一个进程去读这张日志表。

听起来很美好,但实际用起来……嗯,我尽量客观。

优点

  • 实时性高:触发器是数据库内部机制,变更发生时立即触发,延迟极低。
  • 不丢数据:只要触发器写日志表的逻辑没问题,数据不会丢。
  • 能捕获所有操作:包括物理删除。

缺点

  • 对数据库性能影响大:每个 DML 操作都要额外执行一次触发器逻辑,写入日志表。高并发场景下,触发器会成为瓶颈。我见过一个案例,加了触发器后,写入性能直接下降 30%。
  • 维护成本高:触发器是数据库对象,版本管理、迁移、调试都很麻烦。你想想看,几百张表,每张表三个触发器,DBA 想哭。
  • 容易造成死锁:触发器里如果操作了其他表,或者日志表本身有锁竞争,很容易引发死锁。
  • 日志表膨胀快:如果不定期清理,日志表会无限增长。

我的态度:除非你只有一张表、数据量极小、且没有 DBA 团队,否则别用触发器。这个方案在 10 年前还算流行,现在基本被日志型取代了。

四、三种方案对比总表

对比维度 基于日志(Debezium/Canal) 基于轮询 基于触发器
实时性 秒级(<100ms) 分钟级(取决于轮询间隔) 秒级(触发器立即触发)
对业务侵入 无侵入 需加时间戳或自增字段 需建触发器和日志表
数据库压力 低(仅读日志) 高(频繁全表扫描) 高(每个 DML 额外写日志)
数据完整性 高(日志持久化) 低(可能漏数据) 高(触发器保证)
捕获删除 支持 不支持(需逻辑删除) 支持
运维复杂度 高(需 Kafka、Connector) 低(定时任务即可) 中(需管理触发器)
适用场景 高并发、实时同步、数据一致性要求高 小数据量、低频率、非关键业务 不建议使用

五、选型决策流程

说了这么多,到底怎么选?我一般按这个思路来:

  1. 先看数据量:日均变更量超过 10 万条?直接上日志型。
  2. 再看延迟要求:业务要求秒级同步?日志型或触发器型。能接受分钟级?轮询型也可以。
  3. 再看团队能力:有 Kafka 运维经验?Debezium 走起。没有?Canal 或者考虑云厂商的 DTS 服务。
  4. 最后看数据库类型:MySQL 选 Debezium 或 Canal;PostgreSQL 选 Debezium;Oracle 选 OGG 或 Debezium(需配置)。

个人习惯:我现在做新项目,只要涉及增量同步,默认方案就是 Debezium + Kafka + Kafka Connect。虽然前期搭建麻烦点,但后面基本不用管,稳得很。

六、三种方案架构对比图

下面这张图,帮你直观理解三种方案的数据流向差异:

三种 CDC 方案架构对比 业务数据库 方案一:日志型(Debezium/Canal) 读取 binlog/WAL Kafka / 消息队列 下游消费者(实时) 方案二:轮询型(定时任务) 定时 SELECT 查询 应用服务 / 定时任务 下游目标(分钟级) 方案三:触发器型 触发器写入日志表 变更日志表 下游消费者(实时) 关键差异总结 • 日志型:无侵入、实时、高可靠,但需额外组件(Kafka) • 轮询型:简单、兼容性好,但延迟高、压力大、无法捕获删除 • 触发器型:实时、能捕获所有操作,但性能影响大、维护复杂 • 推荐:生产环境首选日志型,小项目可考虑轮询型,触发器型尽量避开

七、我的最终建议

如果你现在要做一个新的 CDC 项目,我的建议很明确:

  • 首选:基于日志的 CDC(Debezium)。这是目前业界公认的最佳实践。虽然搭建麻烦点,但后期运维成本极低,数据一致性有保障。
  • 备选:基于轮询的 CDC。适合数据量小、对实时性要求不高的场景。比如每天同步一次配置表、字典表。
  • 不推荐:基于触发器的 CDC。除非你只有一张表,且没有其他选择。

最后提醒一句:选型不是一劳永逸的。业务在发展,数据在增长,你的 CDC 方案也要跟着迭代。我见过太多项目,一开始用轮询挺爽,半年后数据量上来就崩了。提前做好规划,比事后救火强得多。