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) | 低(定时任务即可) | 中(需管理触发器) |
| 适用场景 | 高并发、实时同步、数据一致性要求高 | 小数据量、低频率、非关键业务 | 不建议使用 |
五、选型决策流程
说了这么多,到底怎么选?我一般按这个思路来:
- 先看数据量:日均变更量超过 10 万条?直接上日志型。
- 再看延迟要求:业务要求秒级同步?日志型或触发器型。能接受分钟级?轮询型也可以。
- 再看团队能力:有 Kafka 运维经验?Debezium 走起。没有?Canal 或者考虑云厂商的 DTS 服务。
- 最后看数据库类型:MySQL 选 Debezium 或 Canal;PostgreSQL 选 Debezium;Oracle 选 OGG 或 Debezium(需配置)。
个人习惯:我现在做新项目,只要涉及增量同步,默认方案就是 Debezium + Kafka + Kafka Connect。虽然前期搭建麻烦点,但后面基本不用管,稳得很。
六、三种方案架构对比图
下面这张图,帮你直观理解三种方案的数据流向差异:
七、我的最终建议
如果你现在要做一个新的 CDC 项目,我的建议很明确:
- 首选:基于日志的 CDC(Debezium)。这是目前业界公认的最佳实践。虽然搭建麻烦点,但后期运维成本极低,数据一致性有保障。
- 备选:基于轮询的 CDC。适合数据量小、对实时性要求不高的场景。比如每天同步一次配置表、字典表。
- 不推荐:基于触发器的 CDC。除非你只有一张表,且没有其他选择。
最后提醒一句:选型不是一劳永逸的。业务在发展,数据在增长,你的 CDC 方案也要跟着迭代。我见过太多项目,一开始用轮询挺爽,半年后数据量上来就崩了。提前做好规划,比事后救火强得多。