一、demo7:实时增量采集-变更数据捕获(CDC)(datax没有的功能)
- mysql-cdc官方文档:https://seatunnel.apache.org/zh-CN/docs/2.3.3/connector-v2/source/MySQL-CDC/
- cdc可以一个seatunnel的cdc任务监控多个表,进行同步
- 必须用mysql8.0.33以上的jdbc驱动

1、seatunnel支持几个数据库的CDC?
-
https://seatunnel.apache.org/zh-CN/docs/2.3.12/connector-v2/source
官方支持的 CDC 源连接器
1、MongoDB CDC 源连接器
2、MySQL CDC 源连接器
3、Opengauss CDC 源连接器
4、Oracle CDC 源连接器
5、PostgreSQL CDC 源连接器
6、SQL Server CDC 源连接器
7、TiDB CDC 源连接器
2、CDC的seatunnel服务启动后,不会停止
一个标准的CDC(Change Data Capture)任务,其设计目标就是"持续运行,永不停止"的流式服务。
-
核心区别:
- 离线/批处理任务 :
job.mode = "BATCH"。执行一次全量或增量的SQL查询,处理完现有数据后,任务自然结束。 - CDC/流处理任务 :
job.mode = "STREAMING"。启动后,它会:- 首先进行可选的初始全量快照 (如果配置了
scan.startup.mode = "initial")。 - 然后挂起并持续监听MySQL的binlog文件流。
- 一旦源数据库有任何新的数据变更(增、删、改),任务会立即捕获、处理并写入目标端。
- 这个监听过程理论上会无限期进行下去 ,直到你手动停止任务,或任务因错误而失败。
- 首先进行可选的初始全量快照 (如果配置了
- 离线/批处理任务 :
-
如何停止任务 :在运行SeaTunnel的终端中,通常可以按
Ctrl + C组合键来优雅地停止正在运行的CDC任务。在生产环境中,可能需要通过作业调度或管理平台来发送停止指令。
简单来说,你可以把CDC任务理解为一个 "常驻的订阅服务" ,它订阅了数据库的变更日志,并在有新事件时实时处理。这不同于执行一次就退出的"离线任务"。
- 💡 配置建议与常见问题
- 关于
startup.mode:对于首次启动任务,强烈建议使用initial,这样可以确保先获取一份完整的当前数据快照,之后再无缝衔接增量变更。如果设为latest,则会丢失所有历史数据,只监听启动后的新变更。 - 关于
server-id:生产环境中务必手动设置一个唯一值,避免使用随机值可能导致的冲突,从而引发任务不稳定。
3、cdc模式与jdbc模式
- 区别
| 特性维度 | MySQL-CDC (流式处理) | JDBC批处理 (批处理) |
|---|---|---|
任务模式 (job.mode) |
STREAMING |
BATCH |
| 数据来源 | 数据库的二进制日志 (Binlog) | 自定义的 SQL 查询结果集 |
| 数据内容 | 变更事件流 (包含op操作类型、前后镜像数据、元数据) |
静态数据快照 (查询返回的原始行数据) |
| 配置核心 | table-names (指定要监控的表) |
query 或 table + sql (指定要查询的SQL) |
| 同步类型 | 实时增量 (可先全量快照,再持续增量) | 一次性全量/批量增量 |
| 输出持续性 | 持续运行,直到手动停止 | 自动结束,数据读取完毕后任务停止 |
| 典型场景 | 实时数仓、实时分析、异地容灾 | T+1报表、数据迁移、历史数据补录 |
| 对源库压力 | 增量阶段持续低压力读取Binlog | 每次执行查询时产生一次性压力 |
| 数据完整性 | 可保证不丢不重 (Exactly-once) | 依赖查询条件,可能重复或遗漏 |
- 区别图
text
+-------------------+ +------------------------------+
| 开始数据同步 | | CDC流处理路径 |
+-------------------+ +------------------------------+
| |
v v
+-------------------+ +------------------------------+
| 选择同步模式 |-----> | 1. 指定表名 |
| (决策点) | | table-names=["db.tbl"] |
+-------------------+ +------------------------------+
| |
| v
| +------------------------------+
| | 2. 连接器读取表结构 |
| +------------------------------+
| |
| v
| +------------------------------+
| | 3. 全量阶段: 读取快照 |
| +------------------------------+
| |
| v
| +------------------------------+
| | 4. 增量阶段: 持续监听Binlog |
| +------------------------------+
| |
| v
| +------------------------------+
| | 5. 输出结构化变更事件 |
| | (+I/-U/+U/-D 等) |
| +------------------------------+
| |
| |
v v
+-------------------+ +------------------------------+
| 批处理JDBC路径 | | |
+-------------------+ | 数据汇聚 |
| | (写入Sink) |
v | |
+-------------------+ +------------------------------+
| 1. 自定义SQL查询 | ^
| SELECT ... | |
+-------------------+ |
| |
v |
+-------------------+ |
| 2. 执行查询 |--------------------+
| 读取结果集 |
+-------------------+
-
图2

-
cdc下,无法用source的query定制sql过滤
-
如果要做数据清洗转换、过滤,只能再transform中做
在MySQL-CDC模式下,你通常无法像使用普通的JDBC Source那样,在 source 模块里通过一个自定义的 query 参数(例如 SELECT * FROM ... WHERE ...)来指定任意SQL语句。
CDC不支持自定义query的主要原因:
-
数据来源不同
- JDBC批处理 :数据来源于你自定义的SQL查询结果集。连接器只是执行并返回这个结果。
- MySQL-CDC :数据来源于数据库的二进制日志(Binlog)。CDC连接器(底层基于Debezium)会将自己伪装成一个MySQL副本,持续接收并解析原始的行级别变更事件流。
-
数据形态不同
- JDBC批处理:你查询出来的是什么数据,同步的就是什么数据。
- MySQL-CDC :它输出的是变更事件 ,每条记录不仅包含变更后的数据(
after状态),还包含变更类型(op字段,如+I表示插入,-U表示更新前,+U表示更新后,-D表示删除)以及元数据(如源库、表、时间戳等)。自定义的SELECT语句无法生成这种结构化的变更事件。
4、 如何在CDC模式下实现"筛选"或"转换"
虽然无法在数据源头(source)进行筛选,但你有多种方式在后续环节处理数据:
| 方法 | 实施位置 | 说明 |
|---|---|---|
| 1. 使用 Transform 转换 | SeaTunnel 配置文件的 transform 部分 |
这是最常用和推荐的方式。你可以在数据流出Source后、写入Sink前,通过SQL语句进行过滤、字段选择、重命名等操作。 |
| 2. 在 Sink 中处理 | Sink 连接器的配置中 | 部分Sink支持在生成写入语句时进行条件过滤或字段映射,但能力有限,不如Transform灵活。 |
| 3. 启用 Schema 演进 | 表级别同步 | 通过只同步部分列的方式间接实现"列筛选",但这需要表结构预先变更,且通常用于长期同步场景。 |
5、CDC可以同时监控多张表,进行实时同步
当你需要用一个CDC任务监控多个表时,SeaTunnel的配置非常直观。关键在于源端(Source)的"一对多"配置 ,以及Sink的"一对一"自动映射。
📝 如何配置"一对多"CDC监控
你只需要在 source 部分的 table-names 列表中指定所有需要监控的表即可。
hocon
source {
MySQL-CDC {
base-url = "jdbc:mysql://192.168.1.107:51382/cs1"
username = "root"
password = "zysoft"
database-names = ["cs1"]
# 核心:在列表中添加多个表,格式必须是:数据库名.表名
table-names = [
"cs1.t_8_100w", # 表1
"cs1.order_table", # 表2
"cs1.user_profile" # 表3
# ... 可以继续添加更多表
]
startup.mode = "initial"
server-id = 5400
server-time-zone = "Asia/Shanghai"
}
}
🎯 Sink的配置:自动路由与并行写入
SeaTunnel的JDBC Sink有一个非常强大的特性:自动表路由 。你几乎不需要为多表同步做特殊配置。
1. 核心配置(与单表一致,关键在 table 参数):
hocon
sink {
jdbc {
url = "jdbc:mysql://192.168.1.107:51382/cs2"
driver = "com.mysql.cj.jdbc.Driver"
user = "root"
password = "zysoft"
generate_sink_sql = true
database = "cs2" # 目标数据库
# 核心技巧:使用变量动态匹配来源表名
table = "${table_name}"
# table = "prefix_${table_name}" # 也可以加前缀
# table = "${database_name}_${table_name}_suffix" # 或使用库名、后缀
schema_save_mode = "CREATE_SCHEMA_WHEN_NOT_EXIST"
data_save_mode = "APPEND_DATA"
batch_size = 5000
# ... 其他连接和调优参数保持不变
}
}
关键说明:
${table_name}和${database_name}是SeaTunnel的内置变量 。运行时,它们会自动被替换为上游CDC数据记录中携带的源表名 和源数据库名。- 这样,
cs1.t_8_100w的数据会自动写入cs2.t_8_100w,cs1.order_table的数据会自动写入cs2.order_table,实现完美的 1:1 映射。
2. 如果需要对不同表采用不同的写入策略怎么办?
你需要为每个表单独配置一个 sink 模块,并使用 filter 条件进行路由:
hocon
sink {
# Sink 1: 专门处理 t_8_100w 表
jdbc {
# 通过目标表名固定,明确写入哪个表
table = "t_8_100w_target"
# 使用 filter 只让来自特定源表的数据流入此sink
source_table_name = "t_8_100w"
# ... 其他配置
}
}
sink {
# Sink 2: 专门处理 order_table 表,可以采用不同的 data_save_mode 等
jdbc {
table = "order_table_target"
source_table_name = "order_table"
data_save_mode = "DROP_DATA" # 例如,对这个表采用清空重灌策略
# ... 其他配置
}
}
💡 重要提醒与最佳实践
- 目标表结构 :确保目标数据库
cs2中已经存在与源表结构兼容的表(或启用schema_save_mode = "CREATE_SCHEMA_WHEN_NOT_EXIST"让SeaTunnel自动创建)。 - 性能与隔离 :监控多表时,所有表的变更会共用同一个数据流。如果某个表变更异常频繁,可能会轻微影响其他表的同步延迟。对于重要性或流量差异极大的表,建议拆分到独立的CDC任务中,以获得更好的隔离性和可维护性。
- 初始快照 :当
startup.mode = "initial"时,任务启动时会依次对所有监控表进行全量快照读取。请确保数据库有足够资源应对同时进行的多个全表扫描。
总结:对于大多数"多表同步到对应结构目标表"的场景,你只需要在 source 中列出多个表,然后在 sink 中配置 table = "${table_name}" 即可,SeaTunnel会自动完成路由和写入。
如果你需要对特定表进行特殊的数据转换,可以在 transform 部分使用SQL,并同样通过 filter 或条件判断来区分不同表的数据流。
路由filter
- 路由与过滤 :如果你希望数据有选择地 流入不同的
sink,而不是全部复制到每一个sink,则需要在每个sink前配置filter或使用侧流输出等更高级的API(在配置文件中通常通过条件表达式实现)。
💡 针对你"多表CDC"场景的配置建议
结合你之前的问题,一个典型的多表CDC同步到不同目标表的配置如下:
hocon
source {
MySQL-CDC {
table-names = ["cs1.t_order", "cs1.t_user", "cs1.t_log"]
# ... 其他配置
}
}
sink {
# 订单表 -> 订单归档库
jdbc {
table = "t_order_archive"
# 使用filter,只同步t_order表的数据
filter {
source_table_name == "t_order"
}
# ...
}
# 用户表 -> 用户分析库
jdbc {
table = "t_user_analysis"
filter {
source_table_name == "t_user"
}
data_save_mode = "OVERWRITE" # 对这个表采用覆盖策略
# ...
}
# 日志表 -> 日志中心(这里示例写入HDFS)
hdfs {
path = "/data/lake/log/${source_table_name}/dt=${now(date='yyyy-MM-dd')}"
filter {
source_table_name == "t_log"
}
# ...
}
}
二、实现Mysql-CDC的步奏

1、查看MySQL Binlog是否开启、开启
sql
-- 最直接的查看方式
SHOW VARIABLES LIKE 'log_bin';
-- 更详细的查看,会显示binlog的文件名和路径
SHOW MASTER STATUS;
-- 查看binlog的格式,确认是否为ROW
SHOW VARIABLES LIKE 'binlog_format';
-- 查看binlog镜像模式,确认是否为FULL
SHOW VARIABLES LIKE 'binlog_row_image';

-
如果没开启binlog,需要修改mysql配置文件,然后重启
[mysqld]
server-id = 123 # 设置一个唯一的服务器ID[citation:2]
log_bin = /var/lib/mysql/mysql-bin # 开启binlog并指定路径
binlog_format = ROW # 必须设置为ROW模式[citation:2][citation:3][citation:5]
binlog_row_image = FULL # 必须设置为FULL[citation:2][citation:4]
expire_logs_days = 10 # 日志保留天数,建议至少2天[citation:2]
2、Mysql-CDC常用参数
| 参数组 | 参数名 | 类型 | 必须 | 默认值 | 说明与注意事项 |
|---|---|---|---|---|---|
| 基础连接 | base-url |
String | 是 | - | JDBC连接字符串 ,格式如 jdbc:mysql://主机:端口/数据库名。这是建立连接的基础。 |
username / password |
String | 是 | - | 数据库用户名和密码。确保用户有复制(REPLICATION)权限。 | |
| 监控范围 | database-names |
List | 否 | - | 要监控的数据库名列表 。若不指定,则需在table-names中完整指定。 |
table-names |
List | 是 | - | 要监控的表名列表 。格式必须为 数据库名.表名 ,例如 inventory.products。 |
|
| 启动与停止 | startup.mode |
Enum | 否 | initial |
启动模式 ,决定从何处开始读取: • initial :先做全量快照,再持续读增量 (常用)。 • earliest:从最早可用的binlog位置开始。 • latest:仅从最新位置开始读增量。 • specific:从指定binlog文件位置开始。 |
startup.specific-offset.file |
String | 否 | - | 当 startup.mode='specific' 时必须 ,指定起始的binlog文件名。 |
|
startup.specific-offset.pos |
Long | 否 | - | 当 startup.mode='specific' 时必须 ,指定起始的binlog位置。 |
|
stop.mode |
Enum | 否 | never |
停止模式,目前文档显示主要选项是 never(即持续运行)。 |
|
| 性能与调优 | server-id |
String | 否 | 随机 | 非常重要 !指定CDC客户端的唯一ID(如5400)或范围(如5400-5408),不能与MySQL集群中任何现有服务器ID冲突。 |
server-time-zone |
String | 否 | UTC | 数据库服务器的会话时区,建议设置为 Asia/Shanghai 以正确解析时间戳。 |
|
snapshot.split.size |
Integer | 否 | 8096 | 表快照读取时每个分块的行数,影响全量阶段读取并行度和内存使用。 | |
incremental.parallelism |
Integer | 否 | 1 | 增量读取阶段的并行度,对于高流量表可适当调大以提升消费速度。 | |
| 高级特性 | exactly_once |
Boolean | 否 | true | 是否启用精确一次语义,通常保持默认以确保数据不丢不重。 |
debezium.* |
Config | 否 | - | 透传Debezium底层引擎的属性,用于实现更精细的控制(如跳过快照、处理特殊数据类型)。 |
三、2.9.2、演示Mysql-CDC(单表)
- 建表
sql
-- demo7-1-mysql-cdc2mysql-qxzh-st-107.conf
CREATE TABLE cs2.`t_8_100w_imp_st_qxzh_cdc_demo7_1` (
`id` bigint NOT NULL COMMENT '主键',
`user_name` varchar(2000) NULL COMMENT '名字',
`sex` varchar(20) null COMMENT '性别:男;女',
`decimal_f` decimal(32, 6) NULL COMMENT '大数字',
`phone_number` varchar(20) COMMENT '电话',
`age` int NULL COMMENT '字符串年龄转数字',
`create_time` timestamp COMMENT '新增时间',
`description` longtext NULL COMMENT '大文本',
`address` varchar(2000) NULL COMMENT '空地址转默认值:未知',
PRIMARY KEY (`id`)
);
- 执行语句
properties
# demo7-1-mysql-cdc2mysql-qxzh-st-107.conf
sh /data/tools/seatunnel/seatunnel-2.3.12/bin/seatunnel.sh --config /data/tools/seatunnel/myconf/demo7-1-mysql-cdc2mysql-qxzh-st-107.conf -m local
- conf
properties
# demo7-1-mysql-cdc2mysql-qxzh-st-107.conf
env {
# 并行度(线程数)
execution.parallelism = 5
# 任务模式:BATCH:批处理模式;STREAMING:流处理模式(CDC的关键)
job.mode = "STREAMING"
}
source {
MySQL-CDC {
base-url = "jdbc:mysql://ip:port/cs1"
username = "root"
password = "zysoft"
# query在cdc中无效
# 数据库
database-names = ["cs1"]
# 监控的表,必须带数据库名(The table name needs to include the database name, for example: database_name.table_name)
table-names = ["cs1.t_8_100w"]
# 启动模式:'initial'表示先做全量快照,再持续读增量;'latest'表示只从最新位点读增量
# Optional startup mode for MySQL CDC consumer, valid enumerations are "initial", "earliest", "latest" and "specific".
startup.mode = initial
# 启动时间,可以设置这个时间之后再启动。startup.mode=timestamp时,这个参数必须有
# startup.timestamp
# 会生成随机数,非常重要!指定CDC客户端的唯一ID(如5400)或范围(如5400-6408),不能与MySQL集群中任何现有服务器ID冲突。
server-id = 5400
# 停止模式
# stop.mode
# 停止时间。当stop.mode=timestamp时,这个参数必须有
# stop.timestamp
# 数据库服务器的会话时区,建议设置为 Asia/Shanghai 以正确解析时间戳。
server-time-zone = "Asia/Shanghai"
}
}
# 清洗转换(cdc的清洗转换,必须在transform中来做)
transform {
# 1. 字段映射
# 除了Sql插件,还可以用:FieldMapper插件,来映射字段。必须写出目标需要的字段。不写的字段的值不会采集。
FieldMapper {
field_mapper = {
id = id
name = user_name
sex = sex
decimal_f = decimal_f
phone_number = phone_number
age = age
create_time = create_time
description = description
}
}
# 2. 手机号脱敏:13812341234 -> 138****1234
# 3. 年龄转换:字符串转整数(实际生产中,不用转换,也没有内置的转换插件,可以直接保存成功)
# 4. 性别转换:1->男,2->女
# 5. 数据过滤:只保留 age > 25 的记录。
# 6. 地址默认值:空地址设为'未知'
}
sink {
jdbc {
url = "jdbc:mysql://ip:port/cs2"
driver = "com.mysql.cj.jdbc.Driver"
user = "root"
password = "zysoft"
# 生成自动插入sql。如果目标库没有表,也会自动建表
generate_sink_sql = true
# generate_sink_sql=true。所以:database必须要
database = cs2
table = "t_8_100w_imp_st_qxzh_cdc_demo7_1"
# 表不存在时报错(任务失败),一般用:CREATE_SCHEMA_WHEN_NOT_EXIST(表不存在时创建表;表存在时跳过操作(保留数据))
schema_save_mode = "ERROR_WHEN_SCHEMA_NOT_EXIST"
# APPEND_DATA:保留表结构和数据,追加新数据(不删除现有数据)(一般用这个)
# DROP_DATA:保留表结构,删除表中所有数据(清空表)------实现清空重灌
data_save_mode = "APPEND_DATA"
# 批量写入条数
batch_size = 5000
# 批次提交间隔
# batch_interval_ms = 0
# 重试次数
max_retries = 3
# 连接参数
# 连接超时时间300ms
connection_check_timeout_sec = 300
properties = {
useUnicode = true
characterEncoding = "utf8"
serverTimezone = "Asia/Shanghai"
# 关键:启用批量重写
rewriteBatchedStatements = "true"
# 启用压缩
useCompression = "true"
# 禁用服务端预处理
useServerPrepStmts = "false"
}
}
}
- 结果
properties
2025-12-11 15:23:41,170 INFO [o.a.s.e.s.CoordinatorService ] [pool-7-thread-1] - [localhost]:5801 [seatunnel-186786] [5.1]
***********************************************
CoordinatorService Thread Pool Status
***********************************************
activeCount : 2
corePoolSize : 10
maximumPoolSize : 2147483647
poolSize : 10
completedTaskCount : 218
taskCount : 220
***********************************************
2025-12-11 15:23:41,172 INFO [o.a.s.e.s.CoordinatorService ] [pool-7-thread-1] - [localhost]:5801 [seatunnel-186786] [5.1]
***********************************************
Job info detail
***********************************************
createdJobCount : 0
pendingJobCount : 0
scheduledJobCount : 0
runningJobCount : 1
failingJobCount : 0
failedJobCount : 0
cancellingJobCount : 0
canceledJobCount : 0
finishedJobCount : 0
***********************************************
2025-12-11 15:23:46,167 INFO [o.a.s.e.c.j.JobMetricsRunner ] [job-metrics-runner-1051397352734064641] -
***********************************************
Job Progress Information
***********************************************
Job Id : 1051397352734064641
Read Count So Far : 1000009
Write Count So Far : 1000009
Average Read Count : 0/s
Average Write Count : 0/s
Last Statistic Time : 2025-12-11 15:22:46
Current Statistic Time : 2025-12-11 15:23:46
***********************************************
2025-12-11 15:23:46,573 INFO [.s.e.s.c.CheckpointCoordinator] [seatunnel-coordinator-service-8] - wait checkpoint completed: 36
2025-12-11 15:23:46,597 INFO [.s.e.s.c.CheckpointCoordinator] [seatunnel-coordinator-service-8] - pending checkpoint(36/1@1051397352734064641) notify finished!
2025-12-11 15:23:46,597 INFO [.s.e.s.c.CheckpointCoordinator] [seatunnel-coordinator-service-8] - start notify checkpoint completed, job id: 1051397352734064641, pipeline id: 1, checkpoint id:36
2025-12-11 15:23:56,573 INFO [.s.e.s.c.CheckpointCoordinator] [seatunnel-coordinator-service-8] - wait checkpoint completed: 37
2025-12-11 15:23:56,588 INFO [.s.e.s.c.CheckpointCoordinator] [seatunnel-coordinator-service-8] - pending checkpoint(37/1@1051397352734064641) notify finished!
2025-12-11 15:23:56,588 INFO [.s.e.s.c.CheckpointCoordinator] [seatunnel-coordinator-service-8] - start notify checkpoint completed, job id: 1051397352734064641, pipeline id: 1, checkpoint id:37
2025-12-11 15:24:06,573 INFO [.s.e.s.c.CheckpointCoordinator] [seatunnel-coordinator-service-8] - wait checkpoint completed: 38
2025-12-11 15:24:06,589 INFO [.s.e.s.c.CheckpointCoordinator] [seatunnel-coordinator-service-8] - pending checkpoint(38/1@1051397352734064641) notify finished!
2025-12-11 15:24:06,589 INFO [.s.e.s.c.CheckpointCoordinator] [seatunnel-coordinator-service-8] - start notify checkpoint completed, job id: 1051397352734064641, pipeline id: 1, checkpoint id:38
2025-12-11 15:24:16,574 INFO [.s.e.s.c.CheckpointCoordinator] [seatunnel-coordinator-service-8] - wait checkpoint completed: 39
2025-12-11 15:24:16,603 INFO [.s.e.s.c.CheckpointCoordinator] [seatunnel-coordinator-service-8] - pending checkpoint(39/1@1051397352734064641) notify finished!
2025-12-11 15:24:16,603 INFO [.s.e.s.c.CheckpointCoordinator] [seatunnel-coordinator-service-8] - start notify checkpoint completed, job id: 1051397352734064641, pipeline id: 1, checkpoint id:39
- 结果图

四、演示Mysql-CDC(单表-清洗转换)
五、演示Mysql-CDC(多表)
- 演示多个表同时cdc监控,一个conf的job