1. CDC 概念与数据湖基础
各位同学,咱们今天聊 CDC 入湖这件事。说实话,我做了十几年数据架构,见过太多「数据搬着搬着就丢了」的惨案。CDC 这东西,说白了就是数据库的「实时日记本」——你改了哪条记录,它都记下来,然后我们把这些变化同步到数据湖里。
嗯,先别急着上代码。咱们得把几个核心概念掰扯清楚。
1.1 CDC 技术原理
CDC 全称是 Change Data Capture,中文叫「变更数据捕获」。它的核心任务就一个:捕捉源端数据的增量变化,然后以低延迟的方式同步到目标端。
实现 CDC 的主流方式有三种。我按自己的经验排了个优先级,你感受一下。
| 实现方式 | 原理简述 | 侵入性 | 延迟 | 典型场景 |
|---|---|---|---|---|
| 日志解析 | 读取数据库事务日志(如 MySQL binlog、Oracle Redo Log) | 低 | 秒级 | 生产环境核心业务表 |
| 触发器 | 在源表上创建触发器,将变更写入日志表 | 高 | 毫秒级 | 小表、低频变更 |
| 时间戳 | 基于 last_modified 字段轮询增量数据 | 中 | 分钟级 | 非实时、离线同步 |
我的建议:只要数据库版本支持,优先选日志解析。我在项目中遇到过用触发器导致源库性能雪崩的情况——一张千万级订单表挂了触发器,结果业务高峰期直接拖垮了主库。从那以后,我对触发器就特别谨慎。
1.1.1 日志解析——最优雅的方案
日志解析的原理很简单:数据库每次提交事务,都会把变更记录写到事务日志里。CDC 工具(比如 Debezium、Canal)假装自己是一个 Slave,去拉取这些日志,然后解析成结构化的变更事件。
举个例子,MySQL 的 binlog 有三种格式:
- STATEMENT:记录 SQL 语句本身。问题在于,同样的 SQL 在 Slave 上执行结果可能不同(比如用了 NOW())。
- ROW:记录每一行变更前后的值。最精确,也是 CDC 的首选格式。
- MIXED:混合模式,默认用 STATEMENT,遇到不确定操作自动切 ROW。
我个人习惯,生产环境一律开 ROW 格式。为什么?因为只有 ROW 格式才能拿到「变更前」和「变更后」的完整数据,这对数据湖的增量合并至关重要。
避坑指南:我曾经遇到一个项目,binlog 格式是 MIXED,结果某次 UPDATE 语句用了 LIMIT,导致解析出来的变更事件丢了两行数据。排查了整整两天才发现是 binlog 格式的问题。所以,CDC 入湖,binlog_format 必须设为 ROW。
1.1.2 触发器——杀鸡用牛刀
触发器的方式,就是在源表上创建 AFTER INSERT、AFTER UPDATE、AFTER DELETE 触发器,把变更记录写到一张专门的 CDC 日志表里。
它的优点是实时性极高——事务提交的同时,变更数据就已经落表了。但缺点也很明显:
- 对源库有性能影响(每个 DML 都多一次写入)
- 维护成本高(表结构变更时触发器要同步更新)
- 容易造成死锁(触发器里再嵌套事务操作)
说实话,我在生产环境几乎不用触发器做 CDC。除非是那种数据量很小、变更频率极低的配置表,比如「国家代码表」「币种表」这种。
1.1.3 时间戳——简单但粗糙
时间戳方式,就是源表里有一个 last_modified 字段,每次更新时自动更新这个字段。CDC 工具定期轮询:SELECT * FROM table WHERE last_modified > last_sync_time。
这种方式实现最简单,但坑也最多:
- 无法捕获 DELETE 操作(除非用软删除)
- 时间精度不够时可能丢数据(比如同一毫秒内多条更新)
- 轮询间隔决定了延迟下限
我一般只在离线数仓的增量同步场景用时间戳,实时入湖基本不考虑。
1.2 数据湖架构演进
聊完 CDC,咱们看看数据湖。这个演进过程我亲身经历过,从传统数仓到湖仓一体,每一步都是被业务逼出来的。
1.2.1 传统数仓时代
十年前,主流架构是 ETL 到关系型数仓(Teradata、Oracle RAC、Greenplum)。特点是:
- 强 Schema 约束,数据必须先建模再入库
- 存储和计算绑定,扩展成本高
- 只能处理结构化数据
那时候做 CDC 入仓,基本就是每天跑一次批量任务,把昨天的增量数据刷进去。实时?不存在的。
1.2.2 数据湖时代
后来 Hadoop 生态起来了,大家发现可以把原始数据先扔到 HDFS/S3 上,需要的时候再建模。这就是数据湖的雏形。
数据湖的优势很明显:
- 存储廉价,可以存全量历史
- 支持结构化、半结构化、非结构化数据
- Schema on Read,数据入湖时不需要提前建模
但问题也随之而来——数据湖容易变成「数据沼泽」。没有元数据管控,数据入湖之后谁也找不到、谁也看不懂。
注意:我见过最夸张的一个数据湖,里面存了 2000 多张 Parquet 表,但没有任何人知道哪些表是有效的、哪些是测试数据。最后不得不花三个月做了一次元数据治理。所以,数据湖建设,元数据必须先行。
1.2.3 湖仓一体时代
最近几年,Lakehouse 架构成了主流。它把数据湖的廉价存储和数据仓库的 ACID 事务、Schema 管理能力结合在了一起。
核心组件包括:
- 开放表格式:Delta Lake、Apache Iceberg、Apache Hudi
- 统一元数据层:Hive Metastore、AWS Glue Catalog
- 计算引擎:Spark、Flink、Presto/Trino
湖仓一体最大的好处是:CDC 入湖的数据可以直接被查询引擎读取,不需要额外的 ETL 过程。说白了,数据从源库到湖里,再到分析师手里,链路短了很多。
1.3 CDC 入湖场景分析
讲了这么多理论,咱们看看实际场景。CDC 入湖到底用在哪些地方?我总结了四个典型场景。
1.3.1 实时数仓增量同步
这是最常见的场景。业务库(MySQL/Oracle)的增量数据,通过 CDC 实时同步到数据湖的 ODS 层。下游的 DWD、DWS 层再基于 ODS 做流式或微批处理。
举个例子:电商订单表,每天几百万增量。用 CDC 入湖后,分析师可以在 1 分钟内看到最新的订单数据,而不是等第二天的 T+1 报表。
1.3.2 多源数据汇聚
很多公司有多个业务系统,各自用不同的数据库。CDC 可以把这些异构数据源统一汇聚到数据湖里。
我曾经帮一家零售公司做过:MySQL 的订单数据、Oracle 的库存数据、MongoDB 的用户行为数据,全部通过 CDC 入湖到 Iceberg 表里。然后基于 Trino 做跨源联合查询。
1.3.3 数据库迁移与备份
CDC 也可以用来做数据库的在线迁移。先做一次全量快照,然后 CDC 持续同步增量,最后在目标端追平数据。整个过程业务无感知。
嗯,这里要注意:CDC 同步不能保证严格的事务一致性,除非你用了 Kafka 的事务机制或者两阶段提交。所以金融场景要谨慎。
1.3.4 数据版本管理与回滚
数据湖的不可变性(Immutable)特性,天然适合做数据版本管理。CDC 入湖时,每条变更记录都带时间戳和操作类型(INSERT/UPDATE/DELETE)。你可以随时回溯到任意时间点的数据快照。
这个能力在数据审计和故障恢复场景特别有用。比如某天凌晨的批量任务把数据写坏了,你可以直接回滚到前一天的状态。
1.4 本章小结
好了,咱们把 CDC 的三种实现方式、数据湖的演进路线、以及入湖的典型场景都过了一遍。核心就三句话:
- 日志解析是 CDC 的首选方案,低侵入、高可靠
- 湖仓一体是当前最佳实践,兼顾存储成本和查询性能
- 元数据管控是数据湖的灵魂,没有元数据,数据湖就是数据沼泽
下一章,咱们会深入聊 CDC 入湖的元数据模型设计。嗯,先消化这些基础概念,后面才能跟上节奏。