资讯动态

《通过SeaTunnel 把 MySQL 的数据搬进 Doris》小白学习系列

发布时间:2026/10/18 7:11:06 来源:尧图企业网站定制
SeaTunnel Doris MySQL-CDC 数据同步故障排查个人笔记番外篇容量、切分与速度——Doris 能扛多少比 MySQL 快多少系列目录篇标题解决什么问题01好好的 MySQL为什么要搬数据搞懂动机知道这活儿值不值得干02Doris 是个啥认识分析型数据库弄清它和 MySQL 的分工03MySQL CDC 是个啥弄懂数据是怎么自己流过去的04SeaTunnel 是个啥认识搬运工具知道为什么选它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 架构大规模并行处理内部两种角色FEFrontend管元数据、接收 SQL、生成执行计划相当于接待处 调度员。BEBackend存数据、真正跑计算相当于仓库 工人。一台 SQL 过去所有 BE 一起干活每人算自己那一块最后汇总。跟 MySQL 差在哪对比项MySQLDoris定位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 是个啥先搞懂 binlogMySQL 有个东西叫binlog二进制日志。你可以把它想象成一台小票打印机数据库每一次增、删、改打印机都打一张小票上面记着谁、几点、对哪行、干了什么。-- 你在 MySQL 里执行 UPDATE t_patient SET phone 13800000000 WHERE id 10086; ​ -- binlog 里就留下一张小票 -- 2026-10-12 14:23:01 t_patient id10086 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 集群对单机场景太重SeaTunnelCDC 内置、支持多表整库同步、能自动建表、自带 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确认并开启 binlogSHOW VARIABLES WHERE variable_name IN (log_bin, binlog_format, binlog_row_image);期望看到变量期望值log_binONbinlog_formatROWbinlog_row_imageFULL哪个不对就去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 YourStrongPwd2026; 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 YourStrongPwd2026; 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检查清单都打勾再进下一篇MySQLlog_binON、binlog_formatROW、binlog_row_imageFULLMySQLseatunnel 账号 5 个权限齐了MySQL28 张表都有主键Doris库建好了能用 MySQL 客户端连上 9030 端口SeaTunnel两个 connector 装好了SeaTunnelJDBC 驱动在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 YourStrongPwd2026 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 YourStrongPwd2026 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 段参数值说明parallelism2两个并行干活。单机不用开太大job.modeSTREAMING流式任务跑起来就不退出持续跟增量checkpoint.interval10000每 10 秒存档一次也是低峰期数据落到 Doris 的触发点source 段MySQL-CDC参数说明base-urlJDBC 连接串。如果你以后升级 SeaTunnel 版本发现文档里叫url是同一个东西新版改名了table-names28 张表的清单格式必须是库名.表名server-id重点这是 CDC 连接在 MySQL 侧的工牌号MySQL 里不能有两个客户端用同一个号否则会被踢下线。这里给个区间5600-5604留余量。如果你还有别的 CDC 任务比如 Canal记得错开startup.modeinitial 先全量后增量首次上线用这个sink 段Doris——注意看table ${table_name}就是多表路由的玄机参数说明fenodesDoris FE 的 HTTP 端口注意是8030不是 MySQL 协议的 9030database / 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 ) ENGINEOLAP 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 existsserver-id 跟别的同步工具撞了换个区间如5700-5704Doris 报 Label already existslabel-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.modeinitial先全量后增量server-id5600-5604CDC 在 MySQL 的工牌号别撞车sink.label-prefixseatunnel-ihm-cdcDoris 导入的批次前缀全局唯一sink.enable-2pctrue精确一次sink.enable-deletetrue同步删除schema_save_modeCREATE_SCHEMA_WHEN_NOT_EXIST自动建表checkpoint.interval10000存档 数据落库节奏环境前提MySQLbinlogON / ROW / FULL表有主键账号有复制权限Doris≥ 1.1建议 2.0表用 Unique Key 模型SeaTunnel2.3.7装 connector-cdc-mysql connector-dorisMySQL 驱动放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写到这里整个系列就完整了。我建议的阅读节奏第 0104 篇花半小时通读一遍建立概念然后 0507 篇对着屏幕边看边敲一个下午能把这条管道跑起来。哪一篇里有卡住的地方或者你的 28 张表里有特别棘手的比如大表、无主键表、分区表告诉我具体情况我可以接着往下细化。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑