没有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博客

相关推荐
浩浩测试一下8 分钟前
C&&汇编中的调用约定
大数据·汇编·安全·web安全·网络安全·系统安全
鹿衔`16 分钟前
CDH 6.3.2 集群外挂部署 Spark 3.5.7 连接 Paimon 1.1.1 (二)
大数据·分布式·spark
aitoolhub42 分钟前
课程表模板在线制作:稿定设计的实用方案
大数据·深度学习·教育电商·在线设计·教育培训
Lovely_Ruby1 小时前
前端er Go-Frame 的学习笔记:实现 to-do 功能(三),用 docker 封装成镜像,并且同时启动前后端数据库服务
前端·后端
Lear1 小时前
MySQL配置文件优化详解:提升数据库性能的关键参数配置
后端
光影少年1 小时前
node中的peerDependencie含义
后端·node.js·掘金·金石计划
7哥♡ۣۖᝰꫛꫀꪝۣℋ1 小时前
Spring Boot ⽇志
java·spring boot·后端
2301_800256111 小时前
8.3 查询优化 核心知识点总结
大数据·数据库·人工智能·sql·postgresql
samFuB1 小时前
【工具变量】全国社保落户制度改革城市DID数据(2010-2025年)
大数据
互联网资讯2 小时前
融合AI大模型的Geo优化系统服务商如何选?避坑指南
大数据·人工智能·ai搜索优化·geo系统·geo优化系统·geo系统搭建