2. CDC基础概念
在核心银行系统中,账户余额、交易流水、客户信息等数据时刻在变化。下游的信贷风控、反欺诈、数据仓库、实时报表等系统,都需要在业务发生时尽快感知这些变化。传统做法是定时批量抽取(如每晚跑批),延迟高、对源库压力大,还容易漏掉中间状态。CDC(Change Data Capture,变更数据捕获)正是为解决这一问题而生的技术:它识别并捕获数据源中发生的插入、更新、删除操作,将这些变更以事件形式持续输出给下游消费方。
一、CDC的定义与核心价值
CDC的本质是“把数据库内部已经发生的变更,转化为可被外部系统消费的事件流”。它并不重新发明数据,而是复用数据库自身为保证持久性和复制而维护的机制。相比批量抽取,CDC具备三个关键特征:
- 低延迟:变更提交后毫秒到秒级即可被捕获,支撑准实时场景。
- 低侵入:基于日志解析时,无需在业务表上增加触发器或时间戳字段,对源库性能影响小。
- 完整语义:能够区分INSERT、UPDATE、DELETE,并保留变更前后的字段值,便于下游做幂等与回滚。
二、日志解析原理:CDC如何“看见”变更
主流CDC工具的核心原理是解析数据库的预写日志(WAL)或二进制日志(binlog)。以MySQL为例,所有对InnoDB表的修改都会先写入redo log和binlog,binlog以事件形式记录变更。CDC工具伪装成MySQL的从库(replica),向主库发送dump协议请求,主库将binlog事件推送给它。工具解析这些事件,还原出表名、操作类型、变更前后的行数据。
# MySQL binlog 事件示例(简化)
# at 1234
# 事件类型: Table_map, Write_rows, Update_rows, Delete_rows
### INSERT INTO bank.account
### SET
### @1=1001 /* INT meta=0 nullable=0 is_null=0 */
### @2=5000.00 /* DECIMAL(18,2) */
### @3='2024-06-01 10:00:00'
对于PostgreSQL,CDC工具通常基于逻辑复制槽(logical replication slot)读取WAL,将变更解码为逻辑日志;Oracle则通过LogMiner或XStream读取redo log。不同数据库的日志格式差异很大,因此CDC工具往往需要针对每种数据库实现专门的解析器。
三、事务一致性:CDC最容易被忽视的难点
数据库中的一次业务操作往往涉及多行、多表的修改,它们被包裹在一个事务中。如果CDC工具逐行解析并立即发送,下游就可能看到“扣了款但还没记账”的中间状态,导致风控误判或报表对不平。因此,成熟的CDC实现必须保证事务一致性:
- 事务边界识别:解析BEGIN和COMMIT事件,将同一事务内的所有变更聚合为一个批次。
- 按提交顺序投递:只有事务提交后,才将其变更事件按顺序发送,避免未提交数据外泄。
- 位点管理:记录已消费的binlog文件名和偏移量(或LSN),故障重启后从位点继续,保证不丢。
- 幂等消费:由于网络重试可能导致重复投递,下游需基于主键或事务ID做去重,实现“至少一次+幂等=精确一次”的效果。
四、常见CDC工具对比与选型
不同工具在侵入性、延迟、事务支持、运维成本上差异明显。下表从核心银行实战角度进行对比:
| 工具 | 原理 | 事务一致性 | 延迟 | 适用场景 |
|---|---|---|---|---|
| Debezium | 解析binlog/WAL,基于Kafka Connect | 强,按事务聚合 | 毫秒~秒级 | MySQL/PG/Oracle实时入湖、事件驱动 |
| Canal | 伪装MySQL从库解析binlog | 较好,支持事务 | 毫秒级 | 阿里系MySQL生态,轻量级同步 |
| Flink CDC | Flink算子内嵌Debezium | 强,支持Exactly-Once | 毫秒~秒级 | 流批一体、复杂ETL、实时数仓 |
| Oracle GoldenGate | 解析redo log | 强,成熟稳定 | 亚秒级 | Oracle核心系统,商业支持 |
| 触发器方案 | 在表上建触发器写变更表 | 依赖触发器实现 | 秒级 | 无日志权限的遗留系统,但侵入大 |
五、案例复盘:一次余额事件重复消费的排查
某银行将账户余额变更通过Debezium推送到Kafka,下游风控系统消费后更新缓存。上线后发现偶发缓存余额比实际多出一笔。排查发现:Debezium在Kafka Connect重启后,因位点提交策略为“至少一次”,部分事件被重复投递;而风控消费端未做幂等,导致同一笔扣款被应用两次。修复方案是在消费端以“账户号+交易流水号”作为去重键,写入Redis并设置TTL,重复事件直接丢弃。同时将Debezium的offset.flush.interval.ms调小,减少重复窗口。该案例说明:CDC的事务一致性不仅取决于工具,更取决于端到端的消费设计。
理解CDC的定义、日志解析原理、事务一致性机制和工具差异,是构建核心银行实时事件分发体系的基础。只有把“变更如何产生、如何捕获、如何保证不丢不重”这条链路想清楚,下游的事件分发才能稳定可靠。