没有Kafka怎么办?Flink SQL 创建 mysql-cdc 作业

前言

在大数据与实时计算的浪潮中,如何高效、低延迟地捕获和处理业务数据库的变更日志,已成为构建流式数据管道的关键。MySQL-CDC(Change Data Capture)技术正是为此而生,它能够实时监听MySQL数据库的二进制日志(Binlog),精准捕捉数据的插入、更新和删除等变更事件,并将这些事件作为连续不断的流推送到下游处理系统,为实时数仓、数据同步和流式分析提供了源头活水。

与传统依赖定时查询的JDBC连接方式相比,MySQL-CDC带来了一场范式革命。JDBC作业通常以固定的时间间隔轮询拉取数据,无法感知中间的变化,既存在显著的延迟,也可能因频繁查询而对源库造成压力。而CDC则是基于事件的、真正的流式处理,它毫秒级地响应变化,保证了数据的端到端实时性,并且减少了对源库的侵入性。

因此,借助Flink SQL创建MySQL-CDC作业,开发者可以轻松地将数据库变更流与KafkaHudiIceberg等数据湖仓无缝集成,广泛应用于实时数仓ETL、物化视图更新、微服务间缓存同步、审计以及在线机器学习特征更新等核心场景,是实现"流批一体"架构不可或缺的利器。

添加依赖

下载后将flink-sql-connector-mysql-cdc-2.4.0.jar包拷贝到 $FLINK_HOME/lib$DINKY_HOME/extends/flink1.17/ 目录下

bash 复制代码
# mysql-cdc连接器,注意版本兼容性
wget https://repo1.maven.org/maven2/com/ververica/flink-sql-connector-mysql-cdc/2.4.0/flink-sql-connector-mysql-cdc-2.4.0.jar

配置为mysql-cdc连接器的源表

sql 复制代码
CREATE TABLE users
(
    `id`                      BIGINT NOT NULL COMMENT '主键id',
    `user_name`               STRING COMMENT '姓名',
    `sex`                     STRING COMMENT '性别',
    `age`                     BIGINT COMMENT '年龄',
    PRIMARY KEY (`id`) NOT ENFORCED
) WITH (
      'connector' = 'mysql-cdc',
      'hostname' = 'xxx.xxx.xxx.xxx',
      'port' = 'xxxx',
      'username' = 'xxxx',
      'password' = 'xxxx',
      'database-name' = 'xxxx',
      'table-name' = 'users',
      'server-time-zone' = 'Asia/Shanghai',
      'scan.startup.mode' = 'initial', -- 先做全量快照,然后从binlog最新位置开始读取(默认)
--       'scan.startup.mode' = 'earliest-offset', -- 直接跳过快照,从binlog最早位置开始读取。
--       'scan.startup.mode' = 'latest-offset',
      'debezium.skipped.operations' = 'd,t' -- 跳过删除/truncate操作
);
  • 'scan.startup.mode' = 'initial'第一次会做全量读取,后续做增量读取;
  • 'debezium.skipped.operations' = 'd,t'表示源表即使做了delete或者truncate操作,目标表也不会同步执行,这是为了防止源表删库跑路牵连到了目标表;

配置为jdbc连接器的目标表

sql 复制代码
CREATE TABLE users2
(
    `id`                      BIGINT NOT NULL COMMENT '主键id',
    `user_name`               STRING COMMENT '姓名',
    `sex`                     STRING COMMENT '性别',
    `age`                     BIGINT COMMENT '年龄',
    PRIMARY KEY (`id`) NOT ENFORCED
) WITH (
      'connector' = 'jdbc',
      'table-name' = 'users2',
      'url' = 'jdbc:mysql://x.x.x.x:3306/xxxx?useSSL=false&serverTimezone=UTC',
      'username' = 'xxxx',
      'password' = 'xxxx',
      'sink.buffer-flush.max-rows' = '100', -- 根据性能调整,小批量写入
      'sink.buffer-flush.interval' = '5s', -- 根据性能调整,控制写入延迟
--     'sink.parallelism' = '4',               -- 增加写入并发
      'sink.max-retries' = '3' -- 写入失败重试
);

最后sink语句

sql 复制代码
insert into user2
select * from users

多个sink表

如果想在一个作业里将源表的数据,链式传输给多个表,例如上文中从users表同步数据到users2表和users3表,就要再增加一个users3表的jdbc映射,以及insert语句。

sql 复制代码
CREATE TABLE users3
(
    `id`                      BIGINT NOT NULL COMMENT '主键id',
    `user_name`               STRING COMMENT '姓名',
    `sex`                     STRING COMMENT '性别',
    `age`                     BIGINT COMMENT '年龄',
    PRIMARY KEY (`id`) NOT ENFORCED
) WITH (
      'connector' = 'jdbc',
      'table-name' = 'users3',
      'url' = 'jdbc:mysql://x.x.x.x:3306/xxxx?useSSL=false&serverTimezone=UTC',
      'username' = 'xxxx',
      'password' = 'xxxx',
      'sink.buffer-flush.max-rows' = '100', -- 根据性能调整,小批量写入
      'sink.buffer-flush.interval' = '5s', -- 根据性能调整,控制写入延迟
--     'sink.parallelism' = '4',               -- 增加写入并发
      'sink.max-retries' = '3' -- 写入失败重试
);

insert into users3
select * from users;

注意这里的源表还是users,而不是users2users2映射的是jdbc连接器,所以如果源表使用users2的话,users3是不会读取到更新记录的。

由于我这里写的场景比较简单,所以insert into users3的代码很少,如果users表到users2users3表的结构差异比较大,中间做了很多转换,导致insert sql逻辑复杂,那么跳过users2而直接从usersinsert into users3时可读性就会很差。解决办法如下:

sql 复制代码
CREATE TABLE users2_cdc
(
    `id`                      BIGINT NOT NULL COMMENT '主键id',
    `user_name`               STRING COMMENT '姓名',
    `sex`                     STRING COMMENT '性别',
    `age`                     BIGINT COMMENT '年龄',
    PRIMARY KEY (`id`) NOT ENFORCED
) WITH (
      'connector' = 'mysql-cdc',
      'hostname' = 'xxx.xxx.xxx.xxx',
      'port' = 'xxxx',
      'username' = 'xxxx',
      'password' = 'xxxx',
      'database-name' = 'xxxx',
      'table-name' = 'users2',
      'server-time-zone' = 'Asia/Shanghai',
      'scan.startup.mode' = 'initial', -- 先做全量快照,然后从binlog最新位置开始读取(默认)
--       'scan.startup.mode' = 'earliest-offset', -- 直接跳过快照,从binlog最早位置开始读取。
--       'scan.startup.mode' = 'latest-offset',
      'debezium.skipped.operations' = 'd,t' -- 跳过删除/truncate操作
);

insert into users3
select * from users2_cdc;

users2_cdc这个表要使用mysql-cdc连接器,虽然它也是users2表,但是和前文中创建的使用jdbc连接器的users2表要分别创建。以上的两条链路也可以分别写在不同的Flink SQL作业里。

参考

【flinkCDC】Cannot read the binlog filename and position via 'SHOW MASTER STATUS'_caused by: org.apache.flink.util.flinkruntimeexcep-CSDN博客

Linux mysql5.7开启 binlog_liunx mysql查看binlog是否开启-CSDN博客

相关推荐
易安说AI1 小时前
Claude Opus 4.6 凌晨发布,我体验了一整晚,说说真实感受。
后端
易安说AI1 小时前
Ralph Loop 让Claude无止尽干活的牛马...
前端·后端
易安说AI1 小时前
用 Claude Code 远程分析生产日志,追踪 Claude Max 账户被封原因
后端
颜酱2 小时前
图结构完全解析:从基础概念到遍历实现
javascript·后端·算法
Coder_Boy_2 小时前
技术让开发更轻松的底层矛盾
java·大数据·数据库·人工智能·深度学习
2501_944934732 小时前
高职大数据技术专业,CDA和Python认证优先考哪个?
大数据·开发语言·python
九河云4 小时前
5秒开服,你的应用部署还卡在“加载中”吗?
大数据·人工智能·安全·机器学习·华为云
Gain_chance4 小时前
36-学习笔记尚硅谷数仓搭建-DWS层数据装载脚本
大数据·数据仓库·笔记·学习
每日新鲜事4 小时前
热销复盘:招商林屿缦岛203套售罄背后的客户逻辑分析
大数据·人工智能
Coder_Boy_5 小时前
基于SpringAI的在线考试系统-考试系统开发流程案例
java·数据库·人工智能·spring boot·后端