SeaTunnel + Doris + MySQL-CDC 数据同步故障排查个人笔记
番外篇:容量、切分与速度——Doris 能扛多少,比 MySQL 快多少
系列目录
| 篇 | 标题 | 解决什么问题 |
|---|---|---|
| 01 | 好好的 MySQL,为什么要搬数据 | 搞懂动机,知道这活儿值不值得干 |
| 02 | Doris 是个啥 | 认识分析型数据库,弄清它和 MySQL 的分工 |
| 03 | MySQL CDC 是个啥 | 弄懂数据是怎么"自己流过去"的 |
| 04 | SeaTunnel 是个啥 | 认识搬运工具,知道为什么选它 |
| 05 | 动手前的准备 | MySQL / Doris / SeaTunnel 三边环境检查 |
| 06 | 核心实战:28 张表一份配置 | 完整配置 + 启动 + 自动建表 |
| 07 | 跑起来之后 | 验证、监控、常见坑 |
| 附录 | 速查表 | 参数和故障一页查 |
第 01 篇:好好的 MySQL,为什么要搬数据
先说你面对的场景。xxxx_database是个医疗业务库,28 张表里存着病人、挂号、收费、医嘱这些数据。医生护士每天在系统里点点点,每点一下,MySQL 里就多一条记录或者改一条记录。这部分 MySQL 干得非常好。
(但是到项目末期,有些业务开始通过用户行为日志记录的方式去分析用户行为,用户哪个功能使用比较多?哪个页面停留时间长?从而反推出哪些功能基本没用到?等一些分析的业务,这个时候mysql就不太合适了,具体情况我们下面会介绍!!!)
然后领导来需求了:"给我出个报表,统计上个月每个科室的就诊量、平均费用、同比增速。"
这条 SQL 大概长这样:
SELECT dept_name, COUNT(*) AS visit_cnt, AVG(total_fee) AS avg_fee FROM t_visit_record WHERE visit_time >= '2026-09-01' GROUP BY dept_name;问题来了:t_visit_record有 5000 万行,这一跑就是全表扫描。放在 MySQL 上会发生什么?
慢。行存数据库一条条读、一条条算,几分钟起步。
影响业务。这条查询会抢 CPU、抢内存(buffer pool)、抢磁盘 IO,这时候医生点一下"保存医嘱"可能就要转圈圈。业务库最怕的就是这种"重查询"。
加索引也救不了。索引适合"查一个人""改一条单"这种点操作。
GROUP BY dept_name要把每个科室的行都摸一遍,索引帮不上忙。
这不是 MySQL 的锅,是分工问题。MySQL 是 OLTP 数据库(联机事务处理),它设计出来就是干"一收一放"的活儿:查一个病人、插一条挂号、改一条状态。而报表是 OLAP 的活儿(联机分析处理),特点是大范围扫描、聚合、分组、多表关联。
让收银台兼职干统计科的活,两头都干不好。所以业界的标准做法是:
业务库只管业务,另起一个专门做分析的数据库管统计。中间用一条管道,把数据源源不断地搬过去。
这条管道,就是我们要搭的东西。搬过去的数据不仅报表秒出,而且随便查、查挂了也不影响线上业务——最坏的结果不过是"分析库慢了",业务一点事没有。
顺便多说一句:搬过去的另一个好处是数据被"洗"过一遍。28 张表在业务库里是按业务逻辑组织的,到了分析库你可以按分析主题重新组织、加宽表、做汇总、剔除掉不必要的字段,查询效率再上一个台阶。
好,动机讲清楚了。下一篇我们认识一下"专门做分析的数据库"——Doris。
第 02 篇:Doris 是个啥
一句话认识
Apache Doris 是一个分析型数据库(也叫实时数仓),你可以把它理解成"专门为算报表而生的数据库"。它和 MySQL 一样都能用 SQL 查,甚至兼容 MySQL 的通信协议——你的 Navicat、BI 工具、JDBC 代码换个端口就能连上它,这是它对小白特别友好的地方。
但它俩的内脏完全是两套构造。Doris 是 MPP 架构(大规模并行处理),内部两种角色:
FE(Frontend):管元数据、接收 SQL、生成执行计划,相当于"接待处 + 调度员"。
BE(Backend):存数据、真正跑计算,相当于"仓库 + 工人"。一台 SQL 过去,所有 BE 一起干活,每人算自己那一块,最后汇总。
跟 MySQL 差在哪
| 对比项 | MySQL | Doris |
|---|---|---|
| 定位 | OLTP,事务型 | OLAP,分析型 |
| 存储方式 | 行存(一行数据挨着存) | 列存(同一列的数据挨着存) |
| 索引 | B+ 树,适合点查 | 前缀索引 + ZoneMap,适合扫一片 |
| 擅长 | 增删改查单条记录、事务 | 大表聚合、多表 JOIN、报表 |
| 不擅长 | 大范围聚合 | 高频点更新、复杂事务 |
| 事务支持 | ACID 完整 | 基本没有(不支持多表事务) |
| 亿级数据聚合 | 分钟级 | 秒级 |
举个例子讲"列存"为什么快
还是上面那条"按科室统计平均费用"。假设表有 5000 万行、30 个字段。
MySQL 行存:就算你只查
dept_name和total_fee两列,它也得把这 5000 万个"整行"读出来,30 个字段里另外 28 个纯属陪跑。Doris 列存:它只把
dept_name这一列和total_fee这一列的数据块读出来,数据量直接砍掉 90% 多。再加上列存里同类数据挨着放、压缩率高,读得少、算得快。
Doris 的优缺点,咱说实话
优点:
聚合查询快,亿级数据秒级出结果;
标准 SQL + MySQL 协议兼容,上手成本低,BI 工具直接接;
数据导入实时性好(Stream Load 秒级可见);
部署运维相对简单,就 FE、BE 两种角色;
支持多种数据模型(下面细说)。
缺点 / 边界(这个更重要,别拿它当万能药):
不适合当业务库。不支持事务、不擅长高频点查点改,你把 HIS 系统的写入搬 Doris 上,系统会很难受;
UPDATE / DELETE 有代价。虽然支持,但本质是"标记 + 后台合并",不能像 MySQL 那样随便高频率改;
存储有冗余(多副本 + 列存索引),占的空间不算小;
对复杂 SQL 的容错和生态成熟度不如 MySQL。
一句话总结:MySQL 是前台收银台,Doris 是后台统计室。收银台的活统计室干不了,统计室的活收银台干不动。它俩是互补关系,不是替代关系——这也是为什么我们做"同步"而不是"迁移"。
顺带讲个后面会用到的概念:数据模型
Doris 建表时要选一种模型,三种里跟我们相关的:
Duplicate Key:只追加,不去重。适合日志这类只进不出的数据。
Aggregate Key:同 Key 的数据按预设规则自动合并(求和、取最大……)。适合固定口径的汇总表。
Unique Key:同 Key 的数据,新来的覆盖旧的,还能删。CDC 同步必须用这个——因为 MySQL 那边改了一条记录,Doris 这边得能"按主键覆盖";删了一条,这边得能"按主键删掉"。
记住这个结论就够了,第 06 篇建表的时候会用到。
第 03 篇:MySQL CDC 是个啥
先搞懂 binlog
MySQL 有个东西叫binlog(二进制日志)。你可以把它想象成一台小票打印机:数据库每一次增、删、改,打印机都打一张小票,上面记着"谁、几点、对哪行、干了什么"。
-- 你在 MySQL 里执行: UPDATE t_patient SET phone = '13800000000' WHERE id = 10086; -- binlog 里就留下一张"小票": -- 2026-10-12 14:23:01 t_patient id=10086 phone: 旧值 -> 13800000000这玩意本来是给主从复制用的(从库订阅主库的小票来保持同步)。而CDC 就是"Change Data Capture,变更数据捕获"——说白了,我们不去动你的业务,只是蹲在旁边订阅这些小票,MySQL 完全无感知。
数据是怎么"流"过去的
我们用的同步模式叫全量 + 增量,在配置里对应startup.mode = "initial",整个过程分两步:
第一步:全量快照。任务启动时,把 28 张表现有的数据整个抄一遍到 Doris。同时记下"我抄到哪张小票了"。
第二步:无缝切增量。快照抄完,从刚才记下的位置开始读小票,MySQL 后续的每一次增删改,秒级变成 Doris 里的一次变化。
MySQL 那边执行三种操作,Doris 这边的表现是这样的:
| MySQL 操作 | Doris 侧表现 |
|---|---|
INSERT一条挂号 | 新增一行 |
UPDATE改了电话 | 按主键覆盖那一行 |
DELETE删了一条 | 按主键把那行删掉 |
跟"每天凌晨全量导一次"比,好在哪
| 每天全量导 | CDC | |
|---|---|---|
| 数据延迟 | 一天 | 秒级 |
| 删除的数据 | 导不出来,越积越多脏数据 | 自动同步删除 |
| 大表 | 5000 万行导 4 小时 | 快照抄一次,之后只传变化 |
| 对 MySQL 压力 | 每天一次大扫描,很伤 | 只读 binlog,压力很小 |
三个硬性前提(第 05 篇会带你检查)
binlog 开着,且格式是 ROW。CDC 记录的是"行变了",不是"SQL 语句",ROW 格式才能拿到变更前后的值。官方文档明确要求
log_bin = ON、binlog_format = ROW、binlog_row_image = FULL,缺一不可。表必须有主键。Doris 那边要"按主键覆盖、按主键删",没有主键就不知道该覆盖哪行。28 张表最好每张都有主键,实在没有的表要单独特殊处理。
给 CDC 单独建个账号,别用 root。权限需要 SELECT、RELOAD、SHOW DATABASES、REPLICATION SLAVE、REPLICATION CLIENT——最后两个就是"允许订阅小票"的意思。
一个小白容易懵的点
"我这边数据还在变,快照抄到一半怎么办?会不会漏?"
不会。快照开始的瞬间,MySQL 会记下当前小票的位置;快照期间发生的变更都还在小票里排队。快照一结束,从那个位置继续读,两边天衣无缝。这就是initial模式(先全量后增量)放心用的原因。
第 04 篇:SeaTunnel 是个啥,为什么选它
一句话认识
Apache SeaTunnel 是一个数据集成工具,专门干"把数据从 A 搬到 B"这件事。它的世界观特别简单,一个作业就三块:
source(从哪读) -> transform(中间加工,可选) -> sink(写到哪)写作业不写代码,写一份配置文件就行。这对我们这种"只想把数据搬过去、不想学编程"的人太友好了。
为什么是它,不是别人
| 工具 | 情况 |
|---|---|
| Sqoop | 老一代 Hadoop 生态工具,只支持批处理,社区基本停更,不考虑 |
| DataX | 阿里的离线同步工具,好用但不支持 CDC,拿不到增量,做不到秒级 |
| Canal / Debezium | 只负责"抓变更",抓完丢 Kafka,还得自己再写消费者入库,链路长 |
| Flink CDC | 功能强,但要额外部署和运维一整套 Flink 集群,对单机场景太重 |
| SeaTunnel | CDC 内置、支持多表整库同步、能自动建表、自带 Zeta 引擎不用装 Flink、一个配置文件搞定 |
Zeta 引擎是什么
SeaTunnel 早期要跑在 Flink 或 Spark 上。后来社区自己写了个执行引擎,就叫Zeta——SeaTunnel 自带的"发动机",装上就能跑,不用再折腾 Flink。单机能跑(你的场景),加机器也能扩成集群。环境里写的是"Zeta 引擎单机集群",指的就是这个。
为什么这个方案特别适合该场景
一个作业同步 28 张表。SeaTunnel 的 source 支持列出多张表,Doris sink 支持多表路由写入——官方叫 MultiTableSink 能力。用
${table_name}这样的占位符,上游来的数据是哪张表,就自动写进 Doris 的哪张表,不用配 28 个作业。自动建表。28 张表难道在 Doris 手写 28 个建表语句?SeaTunnel 支持在任务启动时按上游表结构自动生成 Doris 建表语句(
schema_save_mode),不想要这个功能也可以自己建,后面都讲。删得掉。MySQL 删一条,Doris 跟着删,靠的是
sink.enable-delete = true,前提是 Doris 表用 Unique Key 模型。断了能续。作业挂了重启,能从上次的位置接着搬,不重不漏。
整个链路的全景图
┌─────────────┐ binlog(小票) ┌──────────────────────┐ Stream Load ┌─────────────┐ │ MySQL │ ──────────────> │ SeaTunnel (Zeta) │ ──────────────> │ Doris │ │ xxxxxx │ MySQL-CDC source │ │ 统计 / 报表 │ │ _database │ 全量快照 + 增量 │ Doris MultiTableSink│ │ │ │ 28 张表 │ │ │ │ 28 张表 │ └─────────────┘ └──────────────────────┘ └─────────────┘ 业务在写 一条管道 BI 来查写作入时,Doris sink 是通过 Doris 自己的Stream Load接口(一个 HTTP 导入接口)批量灌数据的,攒一批写一批,效率很高。
好,基础概念简单介绍了下,到此结束。剩下的几篇就是动手了!!
第 05 篇:动手前的准备
三个地方要做检查,我按顺序过一遍。
一、MySQL 侧
1)确认并开启 binlog
SHOW VARIABLES WHERE variable_name IN ('log_bin', 'binlog_format', 'binlog_row_image');期望看到:
| 变量 | 期望值 |
|---|---|
| log_bin | ON |
| binlog_format | ROW |
| binlog_row_image | FULL |
哪个不对,就去my.cnf的[mysqld]段加上:
[mysqld] server-id = 1 log_bin = mysql-bin binlog_format = ROW binlog_row_image = FULL然后重启 MySQL(改这个参数必须重启才生效)。
2)建同步账号
CREATE USER 'seatunnel'@'%' IDENTIFIED BY 'YourStrongPwd@2026'; GRANT SELECT, RELOAD, SHOW DATABASES, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'seatunnel'@'%'; FLUSH PRIVILEGES;3)确认 28 张表都有主键
SELECT TABLE_NAME, TABLE_ROWS FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'xxxx_database'; -- 检查哪些表没主键 SELECT TABLE_NAME FROM information_schema.TABLE_CONSTRAINTS WHERE TABLE_SCHEMA = 'xxxx_database' AND CONSTRAINT_TYPE = 'PRIMARY KEY';第一句还能顺便看一眼每张表多大,心里有个数。
二、Doris 侧
建个库就行,表后面让 SeaTunnel 自动建:
CREATE DATABASE IF NOT EXISTS xxxx_database;建个同步账号(用 root 也行,测试阶段图省事):
CREATE USER 'seatunnel'@'%' IDENTIFIED BY 'YourStrongPwd@2026'; GRANT LOAD_PRIV, SELECT_PRIV ON xxxx_database.* TO 'seatunnel'@'%';注意:Doris 的 CDC 写入(2PC + 删除)对版本有要求,Doris 1.1 以上才能玩得转,建议 2.0+。
三、SeaTunnel 侧
1)下载解压(2.3.7,跟你的环境一致)
wget https://archive.apache.org/dist/seatunnel/2.3.7/apache-seatunnel-2.3.7-bin.tar.gz tar -zxvf apache-seatunnel-2.3.7-bin.tar.gz cd apache-seatunnel-2.3.72)装插件
SeaTunnel 的发行包默认不带所有连接器,要按需装。编辑config/plugin_config,只留我们要的两个:
--seatunnel-connectors-- connector-cdc-mysql connector-doris --end--然后执行:
sh bin/install-plugin.sh ls connectors/ | grep connector看到connector-cdc-mysql和connector-doris两个目录就对了。
3)放 MySQL 的 JDBC 驱动
Zeta 引擎的驱动是放在lib/目录的(这点跟 Flink 引擎不一样,别放错):
# mysql-connector-java 8.x 放进去 cp mysql-connector-java-8.0.30.jar lib/ ls lib/ | grep mysql4)检查清单(都打勾再进下一篇)
- MySQL:
log_bin=ON、binlog_format=ROW、binlog_row_image=FULL - MySQL:seatunnel 账号 5 个权限齐了
- MySQL:28 张表都有主键
- Doris:库建好了,能用 MySQL 客户端连上 9030 端口
- SeaTunnel:两个 connector 装好了
- SeaTunnel:JDBC 驱动在
lib/里
第 06 篇:核心实战——28 张表一份配置
第一步:把 28 张表的清单生成出来
在 MySQL 里跑这条,直接生成配置文件里要的表名列表:
SELECT CONCAT(' "xxxx_database.', TABLE_NAME, '",') FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'xxxx_database' AND TABLE_TYPE = 'BASE TABLE';把结果复制出来,粘到配置文件里(最后一行的逗号删掉)。28 张表,一个作业全包。
第二步:写配置文件
新建config/mysql2doris_ihm.conf,完整内容如下:
env { parallelism = 2 job.mode = "STREAMING" checkpoint.interval = 10000 } source { MySQL-CDC { username = "seatunnel" password = "YourStrongPwd@2026" base-url = "jdbc:mysql://192.168.1.100:3306/xxxx_database" database-names = ["xxxx_database"] # 这里粘贴第一步生成的 28 张表清单 table-names = [ "xxxx_database.t_patient", "xxxx_database.t_visit_record", "xxxx_database.t_fee_detail" # ... 其余 25 张 ] server-id = 5600-5604 startup.mode = "initial" server-time-zone = "Asia/Shanghai" } } sink { Doris { fenodes = "192.168.1.101:8030" username = "seatunnel" password = "YourStrongPwd@2026" database = "xxxx_database" table = "${table_name}" sink.label-prefix = "seatunnel-ihm-cdc" sink.enable-2pc = "true" sink.enable-delete = "true" schema_save_mode = "CREATE_SCHEMA_WHEN_NOT_EXIST" doris.config { format = "json" read_json_by_line = "true" } } }第三步:逐段讲讲这些参数都啥意思
env 段
| 参数 | 值 | 说明 |
|---|---|---|
| parallelism | 2 | 两个并行干活。单机不用开太大 |
| job.mode | STREAMING | 流式任务,跑起来就不退出,持续跟增量 |
| checkpoint.interval | 10000 | 每 10 秒"存档"一次,也是低峰期数据落到 Doris 的触发点 |
source 段(MySQL-CDC)
| 参数 | 说明 |
|---|---|
| base-url | JDBC 连接串。如果你以后升级 SeaTunnel 版本发现文档里叫url,是同一个东西,新版改名了 |
| table-names | 28 张表的清单,格式必须是库名.表名 |
| server-id | 重点:这是 CDC 连接在 MySQL 侧的"工牌号",MySQL 里不能有两个客户端用同一个号,否则会被踢下线。这里给个区间5600-5604留余量。如果你还有别的 CDC 任务(比如 Canal),记得错开 |
| startup.mode | initial= 先全量后增量,首次上线用这个 |
sink 段(Doris)——注意看,table = "${table_name}"就是多表路由的玄机
| 参数 | 说明 |
|---|---|
| fenodes | Doris FE 的 HTTP 端口,注意是8030不是 MySQL 协议的 9030 |
| database / table | ${table_name}是占位符,上游是t_patient就写进t_patient。想加前缀可以写成dwd_${table_name} |
| sink.label-prefix | 重点:Doris 导入用 label 去重,每个任务必须有自己独一无二的前缀,不能跟别的任务重 |
| sink.enable-2pc | 两阶段提交,配合 checkpoint 做到精确一次。开着 |
| sink.enable-delete | 打开删除同步,MySQL 删数据这边才删得掉 |
| schema_save_mode | 表不存在就自动建表,存在就跳过(稳妥) |
| doris.config | 导入格式用 json,一行一个对象 |
如果自动建表不生效怎么办?个别 2.3.x 小版本对schema_save_mode支持有差异,如果启动报"不认识这个参数",就把这行删掉,自己在 Doris 里手动建表,模板长这样:
CREATE TABLE IF NOT EXISTS `xxxx_database`.`t_patient` ( `id` BIGINT, `name` VARCHAR(100), `phone` VARCHAR(20), `create_time` DATETIME ) ENGINE=OLAP UNIQUE KEY(`id`) -- CDC 必须 Unique Key DISTRIBUTED BY HASH(`id`) BUCKETS 10 PROPERTIES ("replication_num" = "1");字段要跟 MySQL 的列一一对应(顺序也要一致),28 张表可以写个脚本从information_schema.COLUMNS拼出来。单机测试replication_num = 1就行。
第四步:启动
本地模式先试跑(强烈建议先这么跑一次):
cd apache-seatunnel-2.3.7 ./bin/seatunnel.sh --config ./config/mysql2doris_ihm.conf -m local跑稳之后,提交到你的 Zeta 集群:
# 先起集群(已起过就跳过) ./bin/start-cluster.sh # 提交作业 ./bin/seatunnel.sh --config ./config/mysql2doris_ihm.conf启动后控制台会滚动 source 和 sink 的读写统计,第一次是全量阶段,28 张表的数据哗哗往里灌。全量结束后进入增量,日志会安静下来——安静不是挂了,是没有新数据,正常。
第 07 篇:跑起来之后——验证、监控、常见坑
一、验证:三步走
第一步,看全量到位没有。Doris 里查:
USE xxxx_database; SHOW TABLES; -- 28 张表应该都在 SELECT COUNT(*) FROM t_patient; -- 和 MySQL 的行数对一对第二步,测增改。MySQL 里:
INSERT INTO t_patient (id, name, phone) VALUES (999999, '测试', '13800000000'); UPDATE t_patient SET phone = '13900000000' WHERE id = 999999;等十几秒(一个 checkpoint 周期),Doris 里查SELECT * FROM t_patient WHERE id = 999999;,应该看到的是改过之后的电话。
第三步,测删。
DELETE FROM t_patient WHERE id = 999999;Doris 里再查,这行应该消失了。如果删不掉,99% 是sink.enable-delete没配,或者 Doris 表建成了 Duplicate Key(没建对模型)。
二、日常怎么看它活着没
# 作业日志 tail -f logs/seatunnel-engine-server.log # Zeta 集群状态 jps # 应该能看到 SeatunnelServer 进程另外重点看checkpoint 是不是一直在涨(日志里每 10 秒一条),checkpoint 能正常推进 = 管道通着。
三、常见坑速查
| 症状 | 大概率原因 | 解法 |
|---|---|---|
| 任务启动就报 binlog 错误 | binlog 没开 / 不是 ROW 格式 | 回第 05 篇检查,改完重启 MySQL |
| 能连上但报权限不足 | 账号权限少给了 | 补 REPLICATION SLAVE、REPLICATION CLIENT |
| 启动报 "A slave with the same server_uuid/server_id exists" | server-id 跟别的同步工具撞了 | 换个区间,如5700-5704 |
| Doris 报 "Label already exists" | label-prefix 重了 | 每个任务用独立前缀,别复制粘贴我的 |
| MySQL 删了数据 Doris 还在 | enable-delete 没开 / 表不是 Unique Key | 配置 + 建表模型 |
| 数据对不上、有重复 | 表没主键 | 给表加主键,或单独处理 |
| 时间差 8 小时 | 时区没对齐 | 加server-time-zone = "Asia/Shanghai",两边都查一下 |
| 报 ClassNotFound: mysql 驱动 | 驱动放错目录 | Zeta 引擎放lib/,不是plugins/ |
| 任务重启后重灌了一堆数据 | 改了 checkpoint 存储或换了 job name | 保持配置稳定,别乱动 |
四、几个进阶问题
"28 张表数据量差异巨大怎么办?"一张 5000 万、一张 500 行,全量阶段大表拖后腿很正常。可以让大表先单独跑一个作业把全量做完,剩下的表走多表作业,用startup.mode = latest只补增量。不过初次上线图省事,一个作业扛下来也行,就是慢点。
"想加第 29 张表怎么办?"加进table-names,重启作业即可。新表会自动补全量(走 initial 逻辑),老表继续接增量。
"表结构改了呢?"加字段这类 DDL 有一定限制,建议走"停作业 → 改 Doris 表结构 → 重启作业"的流程,别指望它全自动。
附录:一页速查表
架构
MySQL(xxxx_database, 28表) │ binlog ▼ SeaTunnel Zeta ── MySQL-CDC(source) → Doris Sink(MultiTable) │ ▼ Doris(xxxx_database, 28表) ←── BI / 报表关键参数
| 参数 | 我们的值 | 干嘛的 |
|---|---|---|
| startup.mode | initial | 先全量后增量 |
| server-id | 5600-5604 | CDC 在 MySQL 的工牌号,别撞车 |
| sink.label-prefix | seatunnel-ihm-cdc | Doris 导入的批次前缀,全局唯一 |
| sink.enable-2pc | true | 精确一次 |
| sink.enable-delete | true | 同步删除 |
| schema_save_mode | CREATE_SCHEMA_WHEN_NOT_EXIST | 自动建表 |
| checkpoint.interval | 10000 | 存档 + 数据落库节奏 |
环境前提
MySQL:binlog=ON / ROW / FULL,表有主键,账号有复制权限
Doris:≥ 1.1(建议 2.0+),表用 Unique Key 模型
SeaTunnel:2.3.7,装 connector-cdc-mysql + connector-doris,MySQL 驱动放
lib/
命令
# 本地试跑 ./bin/seatunnel.sh --config ./config/mysql2doris_ihm.conf -m local # 起集群 + 提交 ./bin/start-cluster.sh ./bin/seatunnel.sh --config ./config/mysql2doris_ihm.conf # 看日志 tail -f logs/seatunnel-engine-server.log写到这里整个系列就完整了。我建议的阅读节奏:第 01~04 篇花半小时通读一遍建立概念,然后 05~07 篇对着屏幕边看边敲,一个下午能把这条管道跑起来。哪一篇里有卡住的地方,或者你的 28 张表里有特别棘手的(比如大表、无主键表、分区表),告诉我具体情况,我可以接着往下细化。