一、CDC技术概述:从一次深夜故障说起
我记得那是几年前的一个深夜,系统告警声把我从睡梦中拽了起来。核心业务库的同步延迟已经超过15分钟,用户订单数据对不上,运营那边炸了锅。我登录上去一看,全量同步任务卡死,批处理窗口被锁,整个数据链路像堵死的下水道。
那次之后,我下定决心把增量同步方案彻底重构。而CDC,就是那把钥匙。
1.1 什么是CDC?说白了就是“只抓变化”
CDC的全称是Change Data Capture,中文叫变更数据捕获。它的核心思想很简单:不每次全量搬数据,只捕获并同步源端发生的变化。
你想想看,一个电商系统每天产生几千万条订单,但真正新增或修改的订单可能只占5%。如果每次都全量同步,99%的IO和网络带宽都浪费在重复数据上。CDC就是解决这个问题的。
CDC的核心价值: 从“全量搬运”转向“增量捕获”,延迟从分钟级降到秒级甚至毫秒级,资源消耗降低一个数量级。
我在项目中见过太多团队,上来就写定时任务跑全量,结果数据量一上来就崩。其实CDC不是什么新概念,但直到近些年才真正普及——因为数据库日志解析技术成熟了。
1.2 CDC的应用场景:不只是数据同步
很多人以为CDC就是做数据同步用的。嗯,这确实是它最广的应用,但远不止于此。我列几个实际场景给你看:
| 场景 | 说明 | 我见过的典型问题 |
|---|---|---|
| 数据库实时同步 | 从MySQL同步到ES、ClickHouse、Hadoop等 | 全量同步导致源库IO打满,业务响应变慢 |
| 缓存失效/更新 | 数据库变更后自动刷新Redis缓存 | 缓存与数据库不一致,用户看到脏数据 |
| 微服务事件驱动 | 订单创建后触发库存、物流、通知等下游服务 | 消息丢失或重复消费,业务状态错乱 |
| 数据仓库实时入仓 | 将OLTP数据实时流入OLAP系统 | T+1报表太慢,业务决策滞后 |
| 审计与合规 | 记录所有数据变更历史,用于追溯 | 手动埋点遗漏,审计不通过 |
我的建议: 如果你还在用定时任务做数据同步,先问问自己:业务能接受多少延迟?如果超过10秒就受不了,那CDC几乎是唯一选择。
1.3 CDC的三种常见实现方案
CDC的实现方式,说白了就三条路:基于日志、基于触发器、基于时间戳。每条路都有它的脾气,我挨个给你讲讲。
1.3.1 基于日志(Log-Based)—— 最推荐的方式
这是目前最主流、最可靠的CDC方案。原理很简单:数据库的binlog(MySQL)、WAL(PostgreSQL)、Redo Log(Oracle)里,本来就记录了所有数据变更。CDC工具直接读取这些日志,解析出INSERT、UPDATE、DELETE操作,然后同步到目标端。
优点:
- 对源库几乎零侵入,不需要改表结构、加触发器
- 能捕获所有变更,包括DDL操作
- 延迟极低,毫秒级
缺点:
- 需要数据库开启日志功能(MySQL要开binlog)
- 日志格式解析复杂,不同数据库版本有差异
- 日志清理策略需要谨慎配置
避坑指南: 我曾经遇到一个项目,binlog保留时间只设了24小时,结果CDC任务挂了半天,恢复后日志已经被清理,只能重新全量同步。建议至少保留72小时,给故障恢复留足缓冲。
1.3.2 基于触发器(Trigger-Based)—— 老派但有效
在源库的表上创建触发器,当数据发生INSERT、UPDATE、DELETE时,触发器把变更记录写入一张专门的日志表。CDC工具再从日志表里拉取数据。
优点:
- 实现简单,不依赖数据库日志
- 可以自定义捕获哪些字段、哪些操作
缺点:
- 对源库性能有影响,每个DML操作都多一次写入
- 需要修改源库结构(加触发器、加日志表)
- DDL操作无法捕获
- 触发器本身可能成为故障点
我的看法: 触发器方案现在用得越来越少了。除非你用的是不支持日志解析的老旧数据库,否则我建议你优先考虑日志方案。触发器就像在业务代码里埋点——侵入性太强,出了问题排查起来很痛苦。
1.3.3 基于时间戳(Timestamp-Based)—— 简单但有限
在源表上加一个last_modified或update_time字段,每次更新时更新这个时间戳。CDC任务定期查询“时间戳大于上次同步时间”的数据,拉取增量。
优点:
- 实现最简单,不需要额外组件
- 对数据库版本无要求
缺点:
- 无法捕获DELETE操作(除非软删除)
- 时间戳精度问题,同一毫秒内的变更可能漏掉
- 依赖业务代码正确更新时间戳
- 不是真正的实时,取决于轮询频率
避坑指南: 我曾经接手过一个项目,时间戳字段是应用层更新的,结果某个接口忘了更新,导致大量数据漏同步。如果你非要用时间戳方案,建议在数据库层面用DEFAULT CURRENT_TIMESTAMP ON UPDATE来保证。
1.4 三种方案对比:一张表说清楚
| 维度 | 基于日志 | 基于触发器 | 基于时间戳 |
|---|---|---|---|
| 源库侵入性 | 低(只需开启日志) | 高(改表结构) | 中(加字段) |
| 实时性 | 毫秒级 | 秒级 | 分钟级(取决于轮询间隔) |
| 捕获DELETE | 支持 | 支持 | 不支持(需软删除) |
| 捕获DDL | 支持 | 不支持 | 不支持 |
| 性能影响 | 极低 | 中等 | 低(查询压力) |
| 实现复杂度 | 高 | 中 | 低 |
| 推荐场景 | 生产环境、高并发、低延迟 | 老旧数据库、无日志支持 | 非关键业务、数据量小 |
1.5 CDC核心架构:一张图看懂
下面这张图是我自己总结的CDC核心架构。说白了,不管用哪种方案,整体流程都跑不出这个框架:
从这张图你能看到,不管底层用哪种捕获方式,最终都要经过CDC引擎的解析、过滤、转换,再写入目标端。我个人习惯把CDC引擎看作一个“数据翻译官”——它把数据库的变更事件翻译成下游系统能理解的格式。
1.6 选型建议:到底该用哪种?
说了这么多,你可能想问:那我到底该选哪种?我的建议很简单:
- 新项目、生产环境、数据量大: 无脑选基于日志。Canal、Debezium、Maxwell这些工具都很成熟。
- 老旧数据库、不支持日志: 只能选触发器,但要做好性能评估。
- 非关键业务、数据量小、快速实现: 时间戳方案可以应急,但别当长期方案。
最后提醒一句: 不管你选哪种方案,一定要做好监控和容错。CDC链路一旦断了,数据不一致的问题会像滚雪球一样越滚越大。我见过太多团队只关注“怎么接入”,忽略了“怎么运维”,结果上线后天天救火。