2、CDC核心原理:日志捕获机制、增量数据识别、数据变更事件
CDC这东西,说白了就是让数据库自己告诉我们它变了什么。而不是我们每隔几秒去问它“你变了没?”。我个人习惯把CDC的核心拆成三个环节:怎么抓到变化、怎么识别哪些是增量、怎么把变化包装成事件。这三个环节搞清楚了,选型就不会抓瞎。
2.1 日志捕获机制:数据库的“黑匣子”
几乎所有主流数据库都会记录事务日志。MySQL有binlog,PostgreSQL有WAL,Oracle有Redo Log。这些日志原本是为了崩溃恢复和主从复制用的。但你想,主从复制不就是最原始的CDC吗?
我在项目中遇到过不少团队,想自己写脚本去查表的LAST_MODIFIED时间戳来做增量。嗯,小数据量还行,一旦上了千万级,性能直接崩。而且你根本捕获不到删除操作——除非你用软删除。
所以,真正的CDC一定要走日志。日志捕获机制主要有两种模式:
| 模式 | 原理 | 典型代表 | 我踩过的坑 |
|---|---|---|---|
| 基于日志解析 | 直接读取数据库的事务日志文件,解析成结构化数据 | Debezium、Canal、Maxwell | binlog格式没配成ROW,解析出来全是SQL语句,根本没法用 |
| 基于触发器/API | 在表上建触发器,或者调用数据库的变更跟踪API | SQL Server Change Tracking、Oracle GoldenGate | 触发器对源库性能影响很大,生产环境慎用 |
我个人更倾向于基于日志解析的方式。因为它对源库几乎零侵入。你想想,日志本来就在写,我们只是多了一个消费者而已。
核心原则:日志捕获必须做到“读日志不写日志”,不能反过来往源库写任何东西。否则CDC就变成了另一个压力源。
2.2 增量数据识别:从日志流里捞出“干净”的变化
日志文件是连续的、二进制的、混杂的。里面有事务开始、事务提交、数据变更、检查点、心跳……我们要做的,就是从这堆“噪音”里精准捞出每一行数据的每一次变更。
增量识别的关键步骤,我总结为三步:
- 定位起始点:第一次同步需要知道从哪个日志位置开始。通常是全量快照完成时的日志偏移量。
- 过滤无关操作:只保留INSERT、UPDATE、DELETE。DDL操作、心跳包、检查点全部跳过。
- 还原变更前/后镜像:对于UPDATE,日志里通常只记录变更后的值。但很多场景下我们需要“变更前”的值来做比对或回滚。
这里有个坑。我曾经遇到一个项目,MySQL的binlog格式配的是STATEMENT,结果解析出来的全是UPDATE t SET name='xxx' WHERE id IN (...)这种SQL片段。你根本不知道具体哪几行变了,更拿不到变更前的值。后来我强制要求所有CDC场景下,binlog格式必须设为ROW。这是铁律。
避坑指南:我曾经因为binlog格式没配对,导致增量数据解析出来全是乱码。排查了整整两天才发现是binlog_row_image设成了MINIMAL,只记录了变更列的镜像,主键以外的字段全丢了。生产环境建议用FULL。
2.3 数据变更事件:把日志行变成业务能懂的消息
日志解析出来的是二进制字节流。业务系统看不懂这些。我们需要把它包装成结构化的数据变更事件。
一个标准的数据变更事件,至少包含以下字段:
| 字段 | 说明 | 示例 |
|---|---|---|
op |
操作类型:c=创建,u=更新,d=删除,r=快照读取 | u |
ts_ms |
事件发生的时间戳(毫秒) | 1698123456789 |
before |
变更前的数据行(DELETE和UPDATE有值) | {"id":1,"name":"旧值"} |
after |
变更后的数据行(INSERT和UPDATE有值) | {"id":1,"name":"新值"} |
source |
元数据:库名、表名、日志偏移量、线程ID等 | {"db":"shop","table":"orders"} |
Debezium的Kafka Connect Connector就是按这个格式输出的。我个人觉得这个设计很优雅——它把数据库底层的日志语义,映射成了消息队列里的一条条JSON消息。下游的消费者不用关心你用的是MySQL还是PostgreSQL,统一消费事件就行。
小技巧:如果你用Kafka做事件总线,建议把topic按库名.表名来命名,比如shop.orders。这样下游可以根据topic直接订阅关心的表,不用在消息体里再过滤一遍。
2.4 核心流程总览:一张图看懂CDC
下面这张图,是我自己画的一个CDC核心流程。从源库的日志文件开始,到最终投递到消息队列,每一步都对应我们刚才讲的内容。
你看,整个链路其实不复杂。但每个环节都有细节。日志解析要处理断点续传,增量识别要处理大事务拆分,变更事件要考虑schema演进。这些我们后面会展开讲。
嗯,这一章先到这里。核心就是记住:CDC的本质是把数据库的日志,翻译成业务系统能消费的事件流。后面的章节,我们会围绕这个流程,一个一个环节深入进去。