一、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核心架构图 源数据库 MySQL / PostgreSQL / Oracle 变更源 Binlog / WAL / Redo Log 触发器 + 日志表 时间戳字段 CDC 捕获引擎 解析 / 过滤 / 转换 目标端 Kafka / ES / ClickHouse / 数据湖 说明 1. 源库产生变更 2. 三种方式捕获变更 3. CDC引擎解析并分发 4. 写入目标系统

从这张图你能看到,不管底层用哪种捕获方式,最终都要经过CDC引擎的解析、过滤、转换,再写入目标端。我个人习惯把CDC引擎看作一个“数据翻译官”——它把数据库的变更事件翻译成下游系统能理解的格式。

1.6 选型建议:到底该用哪种?

说了这么多,你可能想问:那我到底该选哪种?我的建议很简单:

  • 新项目、生产环境、数据量大: 无脑选基于日志。Canal、Debezium、Maxwell这些工具都很成熟。
  • 老旧数据库、不支持日志: 只能选触发器,但要做好性能评估。
  • 非关键业务、数据量小、快速实现: 时间戳方案可以应急,但别当长期方案。

最后提醒一句: 不管你选哪种方案,一定要做好监控和容错。CDC链路一旦断了,数据不一致的问题会像滚雪球一样越滚越大。我见过太多团队只关注“怎么接入”,忽略了“怎么运维”,结果上线后天天救火。