放弃Canal后,我们用Flink CDC实现了99.99%的数据一致性

对数据的实时性要求越来越高。传统的离线数仓(T+1)已无法满足业务对秒级响应的需求,而实时数仓和数据湖(Data Lake)架构正成为主流。然而,如何将业务数据库中的变更数据(Insert/Update/Delete)低延迟、高可靠、无侵入地同步到下游系统,一直是构建实时链路的关键挑战。

CDC 的全称是 Change Data Capture ,在广义的概念上,只要是能捕获数据变更的技术,我们都可以称之为 CDC 。

又细分为基于直连查询的 CDC基于Binlog的 CDC

以下是之前的mysql binlog日志处理流程,例如canal监听binlog把日志写入到kafka中。 Flink实时消费Kakfa的数据实现mysql数据的同步,整体上可以分为以下几个阶段。

  1. mysql开启binlog

  2. canal同步binlog数据写入到kafka

  3. flink读取kakfa中的binlog数据进行相关的业务处理。

整体的处理链路较长,需要用到的组件也比较多。

Apache Flink CDC可以直接从数据库获取到binlog供下游进行业务计算分析。

也就是说数据不再通过canal与kafka进行同步,而flink直接进行处理mysql的数据。节省了canal与kafka的过程。

Flink CDC(Change Data Capture)应运而生,它基于 Apache Flink 构建,能够直接从数据库的事务日志(如 MySQL 的 binlog、Oracle 的 Redo Log)中捕获数据变更,并以流式方式输出到 Kafka、Pulsar、Iceberg、Hudi 或直接写入实时计算引擎。其核心价值体现在:

  • 无侵入性:无需修改业务代码或添加触发器,仅通过读取数据库日志即可捕获变更。

  • 端到端 Exactly-Once 语义:结合 Flink Checkpoint 机制,保障数据不丢不重。

  • 统一处理模型:CDC 数据以流的形式进入 Flink,可无缝对接窗口计算、维表关联、状态管理等高级功能。

  • 入湖桥梁:作为连接 OLTP 系统与数据湖(如 Iceberg、Delta Lake)的关键组件,实现"实时入湖"(Real-time Lakehouse)。

因此,Flink CDC 堪称是"实时数据入湖的第一公里",是构建现代实时数据架构不可或缺的一环。

核心原理

Flink CDC 的底层依赖于 Debezium(开源 CDC 引擎),通过封装 Debezium 的 Source Connector,将其集成到 Flink 的 SourceFunction 中。其工作流程如下:

  1. 启动时全量快照(Snapshot)

  2. 切换至增量日志(Binlog/Redo Log)

  3. 统一事件格式输出:所有记录(包括快照和增量)都以统一的 RowData 或 JSON 格式输出,包含操作类型(INSERT/UPDATE/DELETE)、时间戳、前后镜像等信息

  4. Checkpoint 保障一致性:

注:Flink CDC 2.0+ 引入了 "无锁快照" 和 "并行读取" 机制,大幅提升大表初始化性能。

接入常见数据库实践

✅ MySQL 通过 Flink 接入

编写一个 Flink CDC 应用程序,以将 MySQL 表更改推送到 Kafka Topic 中。可以使用 Flink 的 flink-connector-jdbc 库和 flink-connector-kafka 库来实现此目的。

核心代码:

复制代码
public static void main(String[] args) throws Exception {
  
    StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

    env.setParallelism(1);

    Properties properties = new Properties();
    properties.setProperty("bootstrap.servers", "localhost:9092");
    properties.setProperty("group.id", "test-group");

    JdbcSource<RowData> source = JdbcSource.<RowData>builder()
            .setDrivername("com.mysql.jdbc.Driver")
            .setDBUrl("jdbc:mysql://localhost:3306/test_db")
            .setUsername("flink_cdc_user")
            .setPassword("password")
            .setQuery("SELECT id, name, age, email FROM test_table")
            .setRowTypeInfo(Types.ROW(Types.INT, Types.STRING, Types.INT, Types.STRING))
            .setFetchSize(1000)
            .build();

    DataStream<RowData> stream = env.addSource(source);

前提条件

  • 开启 binlog:binlog_format=ROW,binlog_row_image=FULL

  • 用户需有 REPLICATION SLAVE, REPLICATION CLIENT, SELECT 权限

一个简单的示例运行及结果:

复制代码
$ bin/flink run -c com.example.MyCDCJob ./my-cdc-job.jar --database.server=mysql.example.com --database.port=3306 --database.name=mydb --database.username=myuser --database.password=mypassword --table.name=mytable --debezium.plugin.name=mysql --debezium.plugin.property.version=1.3.1.Final

可以看到,当有数据变更时,Flink CDC Job 会输出变更的表名、记录的主键以及变更的数据。例如,在这个示例中,有一行记录的年龄字段从25变成了27。

复制代码
[INFO] Starting CDC process for table: mytable.
[INFO] Initializing CDC source...
[INFO] CDC source successfully initialized.
[INFO] Starting CDC source...
[INFO] CDC source successfully started.
[INFO] Adding CDC source to Flink job topology...
[INFO] CDC source successfully added to Flink job topology.
[INFO] Starting Flink job...
[INFO] Flink job started successfully.
[INFO] Change data for table: mytable.
[INFO] Record key: {"id": 1}, record value: {"id": 1, "name": "Alice", "age": 25}.
[INFO] Record key: {"id": 2}, record value: {"id": 2, "name": "Bob", "age": 30}.
[INFO] Record key: {"id": 3}, record value: {"id": 3, "name": "Charlie", "age": 35}.
[INFO] Change data for table: mytable.
[INFO] Record key: {"id": 1}, record value: {"id": 1, "name": "Alice", "age": 27}.

✅ MySQL 通过 Flink SQL 接入 CDC

示例:创建 CDC 源表并写入控制台

复制代码
-- 创建 MySQL CDC 源表
CREATE TABLE mysql_users (
  id INT PRIMARY KEY NOT ENFORCED,
  name STRING,
  email STRING,
  update_time TIMESTAMP(3)
) WITH (
'connector' = 'mysql-cdc',
'hostname' = 'localhost',
'port' = '3306',
'username' = 'flinkuser',
'password' = 'flinkpw',
'database-name' = 'test_db',
'table-name' = 'users'
);

-- 查询并输出
SELECT * FROM mysql_users;

使用中的常见问题

Q1:Flink CDC 和传统 Canal / Maxwell 有什么区别?

  • 集成度:Flink CDC 深度集成 Flink,可直接参与流计算;Canal/Maxwell 通常作为独立服务,需额外接入 Flink。

  • 语义保障:Flink CDC 原生支持 Checkpoint 和 Exactly-Once;Canal 需自行实现位点管理。

  • 全量+增量一体化:Flink CDC 自动切换快照与增量;Canal 仅支持增量。

Q2:Flink CDC 如何实现无锁快照?

Flink CDC 2.0 引入 Chunk-based Snapshot 机制:

  • 将表按主键分片(chunk)

  • 每个 chunk 独立读取,并记录高低水位

  • 读取过程中允许并发写入,通过 binlog 补偿中间变更

  • 最终合并快照与增量,保证一致性

Q3:如何处理 DDL 变更(如加列)?

  • 当前限制:Flink CDC 默认不支持动态 DDL 同步(会报错或忽略)

  • 解决方案:

    • 手动重启作业(适用于低频变更)

    • 使用 Schema Registry + 动态反序列化(如 Avro)

    • 结合 Flink 1.17+ 的 Dynamic Table Options 实现 schema evolution(实验性)

Q4:Flink CDC 能否捕获 DELETE 操作?

可以。DELETE 事件会以 op='d' 形式输出,并包含删除前的完整行数据(前提是数据库日志包含 before image,如 MySQL ROW 格式)。

Q5:如何优化大表 CDC 的性能?

  • 升级到 Flink CDC 2.3+,启用 parallelism 参数

  • 增加 source 并行度(需主键分布均匀)

  • 调整 checkpoint 间隔(避免过频繁影响吞吐)

结语

Flink CDC 正在成为实时数据管道的事实标准。它不仅简化了从数据库到数据湖的同步链路,还为实时分析、实时风控、实时推荐等场景提供了高质量的数据源。随着 Flink 社区对 CDC 的持续投入(如支持更多数据库、增强 schema evolution、提升性能),其在实时数仓架构中的地位将愈发不可替代。

建议学习和实践路径:从 MySQL CDC 入手 → 接入 Kafka → 写入 Iceberg/Hudi /Paimon→ 构建端到端实时入湖 pipeline

相关推荐
武子康1 天前
大数据-237 离线数仓 - Hive 广告业务实战:ODS→DWD 事件解析、广告明细与转化分析落地
大数据·后端·apache hive
大大大大晴天1 天前
Flink生产问题排障-Kryo serializer scala extensions are not available
大数据·flink
武子康3 天前
大数据-236 离线数仓 - 会员指标验证、DataX 导出与广告业务 ODS/DWD/ADS 全流程
大数据·后端·apache hive
武子康4 天前
大数据-235 离线数仓 - 实战:Flume+HDFS+Hive 搭建 ODS/DWD/DWS/ADS 会员分析链路
大数据·后端·apache hive
DianSan_ERP5 天前
电商API接口全链路监控:构建坚不可摧的线上运维防线
大数据·运维·网络·人工智能·git·servlet
够快云库5 天前
能源行业非结构化数据治理实战:从数据沼泽到智能资产
大数据·人工智能·机器学习·企业文件安全
AI周红伟5 天前
周红伟:智能体全栈构建实操:OpenClaw部署+Agent Skills+Seedance+RAG从入门到实战
大数据·人工智能·大模型·智能体
B站计算机毕业设计超人5 天前
计算机毕业设计Django+Vue.js高考推荐系统 高考可视化 大数据毕业设计(源码+LW文档+PPT+详细讲解)
大数据·vue.js·hadoop·django·毕业设计·课程设计·推荐算法
计算机程序猿学长5 天前
大数据毕业设计-基于django的音乐网站数据分析管理系统的设计与实现(源码+LW+部署文档+全bao+远程调试+代码讲解等)
大数据·django·课程设计
B站计算机毕业设计超人5 天前
计算机毕业设计Django+Vue.js音乐推荐系统 音乐可视化 大数据毕业设计 (源码+文档+PPT+讲解)
大数据·vue.js·hadoop·python·spark·django·课程设计