
新表没同步作业还没报错这个坑我前后踩了三次才彻底搞明白。先说现象MySQL整库同步到Paimon线上跑得好好的业务某天新建了一张表开始写入数据结果第二天一看Paimon里压根没有这张表。检查Flink作业状态RUNNING延迟正常日志里也没有任何异常。重启作业后新表数据进来了但缺的前一段数据还得单独补。整个过程最折磨人的地方在于系统不告诉你“我漏了一张表”一切指标看着都正常数据就是没进来。这个问题的本质是对“整库同步”的机制理解不到位。很多人以为整库同步是一张“动态的大网”MySQL里新建表网会自动把它兜进来。实际上大多数作业启动的那一刻要同步哪些表就已经定死了。后面新建的表除非特殊处理否则不会进入同步范围。这篇就围绕这个坑把架构原理、配置排查、实操方案和验证手段一次性讲清楚给正在做MySQL到Paimon整库同步的朋友做个参考。1. 整库同步的链路与新表“看不见”的根源1.1 一条整库同步链路是怎么拼起来的MySQL整库同步到Paimon主流的做法是Flink CDC加Paimon的Sink。链路大概是这样的Flink CDC的MySQL Source负责读取MySQL的数据变更包括两部分一部分是启动时的一致性快照另一部分是后续的binlog增量。这两部分数据会统一进入Flink的pipeline由Paimon Sink负责写入目标表。Paimon Sink这边做的事情比很多人想象中多目标表不存在时它会自动建表表存在时它会根据schema变化做演进写入过程中还会触发compaction把小文件合并成大文件。这些能力确实强但也容易给人造成错觉好像整个链路是“自适应”的。实际上Paimon Sink的自动建表是被动的它只有收到某张表的数据才知道要为这张表建目标表。如果Source那边压根没把一个新表的数据发过来Paimon这边什么都感知不到。另一个关键点是MySQL binglog格式需要是ROW并且binlog_row_image要设置为FULL否则CDC读取到的主键和前后镜像不完整很多整库同步问题都是从这里开始的。另外CDC作业的server-id在一个MySQL实例下不能重复多个同步任务共用一个实例时server-id重复会导致拉取binlog时互相干扰甚至出现数据断层。1.2 “自动同步新表”这件事到底由谁负责这是全篇最核心的一点同步范围在作业启动时就已经固化了。Flink CDC的MySQL Source在作业启动时会按照配置的表清单去MySQL拉取表结构信息和数据。这个表清单来自两个地方一个是YAML pipeline里的tables或tableList配置另一个是Flink SQL里CREATE DATABASE AS或者CREATE TABLE AS语句中指定的表。无论哪种方式作业启动后这个清单就是固定的。之后MySQL里新建了一张表这个CREATE TABLE的DDL事件确实会出现在binlog里但Flink CDC Source的解析器只会处理当前作业关心的表。新表不在清单里即使DDL事件被看到Source也不会把这张新表动态扩展为流处理中的一张新表。更直接地说新表后续的INSERT、UPDATE事件binlog里都有但Source只按已注册的表去匹配和分发数据新表的数据在Source这一层就被丢弃了。有一种误判是认为Paimon支持schema evolution所以新表也能自动同步。schema evolution解决的是“同一张表的表结构变化”比如加列、改类型而不是“多了一张新表”。这是两个维度的事把两者混在一起排查方向就会跑偏。1.3 新表不同步的三种典型表现我实际排查中遇到的“新表不同步”表现并不完全一样大致分三类第一类目标端完全没有这张表。这种情况最直观Paimon仓库里查不到新表的名字。原因是Source侧表清单里就没有这张表数据根本没进Flink作业Sink自然也不会建表。第二类目标端有表但没有数据。这一类容易迷惑人因为Paimon里能看到表结构说明Sink确实被触发了有数据写入了。但数据可能就是DDL之后的增量而不是完整数据或者只有零星几条。这种往往是新表在作业运行中创建Source因为某种机制确实开始分发它的binlog事件了但缺少了建表之前的历史快照。第三类有表有数据但时间线不连续中间缺了一段。这类问题最隐蔽数据看起来在同步但对比源端会发现缺了一个时间窗口。原因多是作业重启后新表才被纳入清单但重启时表已经存在了全量阶段扫的是“当前快照”快照之前的binlog因为位点跳跃没有补上。遇到新表不同步的问题先判断属于这三种里的哪一种能省掉大量无效排查。2. 五个必查的配置点与原理拆解2.1 表清单的匹配写法与大小写陷阱整库同步的表清单配置最常见的是用正则表达式。在Flink CDC的YAML pipeline里大概是这么写的source: type: mysql hostname: 10.0.0.10 port: 3306 username: cdc_user password: ****** tables: shop\..*注意这个shop\..*在YAML和Java字符串里反斜杠都是转义字符所以正则里的点需要写成\.否则写shop..*也能匹配但语义上容易出问题。如果你写的是精确表名列表比如shop.order, shop.user那新的表进来绝对不会自动同步这个不多解释。大小写是个大坑。MySQL表名在Linux环境下区分大小写但你配置的正则如果写成了Shop\..*而实际表名是小写shop开头那就什么都匹配不到。我自己遇到过明明是匹配规则写对了排查半天最后发现是库名大小写和MySQL里的实际定义不一致。整库同步的匹配规则里有任何大小写差异新表就是静默丢掉连日志都不带提示的。2.2 scan.startup.mode对“新表窗口期”的影响Flink CDC的MySQL Source有两个启动模式最常用的initial和latest-offset。initial模式表示作业启动时先对MySQL里匹配到的表做一次一致性快照再通过binlog追增量。这个模式有两个隐藏问题第一快照阶段并不是瞬间完成的大表全量读取可能耗时数小时。如果在这期间MySQL里新建了一张匹配正则的表而你的CDC版本不支持动态表发现这张新表就不会被纳入当前快照范围。第二快照完成后开始追binlog但新表是在快照开始前还是快照期间创建的是否出现在binlog的位点区间内存在很多边界情况。一旦位点衔接有问题新表数据就缺一段。latest-offset模式则简单直接只从作业启动的位点开始读增量启动之前的数据一概不要。这种模式下作业运行中新建的表理论上后续binlog能够读到但如果Source端表列表依然固定数据一样进不来。所以启动模式只影响“新表的数据从哪个位点开始”不解决“新表是否进入同步范围”的根本问题。2.3 主键策略与Paimon自动建表的隐藏门槛Paimon建表需要主键这是很多整库同步用户忽略的点。MySQL的一张新表如果没有主键或者主键字段在Paimon里不适用整库同步作业在遇到这张表时行为非常关键。Paimon的sink在没有显式主键配置时在建表环节就可能出问题。有的版本会直接把这张表当作无主键表写入时性能骤降有的版本会尝试用整行作为主键但这个动作可能导致表无法正常创建。实际表现就是新表的数据明明已经发到了SinkPaimon里就是建不出表或者建了表但写入一直失败作业还不fail只在日志里报错重试。解决办法通常是在建表规则里为无主键表指定一个合成主键或者配置Paimon append-only表模式。如果整库同步要覆盖几十上百张表建议在同步管道里统一约定主键生成规则不要指望每张新表都天然满足Paimon的主键要求。2.4 权限、binlog格式和server-id的三个冷门坑权限问题在整库同步里比很多人以为的更隐蔽。CDC用户需要至少SELECT、RELOAD、SHOW DATABASES、REPLICATION SLAVE、REPLICATION CLIENT这几个权限。如果权限不够Flink CDC的作业可能正常启动、正常RUNNING但读新库的binlog或表结构时报错被吞掉或直接跳过。尤其是新增了数据库或表后如果权限只授权到了旧库新库的表就是同步不进来。binlog格式必须是ROW而且binlog_row_image得是FULL。如果MySQL那边配置的是MINIMAL或者改过参数没有生效CDC拿不到完整的before镜像Paimon做主键表更新时会出问题表现出来也是“新表数据写不进去”或者“数据一直对不上”。server-id这个参数官方要求每个MySQL CDC作业在同一个MySQL实例下必须唯一。多个作业共用同一个server-idbinlog拉取会发生冲突轻则数据乱序重则其中一个作业直接卡死。整库同步作业本来就涉及大量表一旦server-id冲突新表的数据会不会丢完全看运气。2.5 DDL同步、schema演进和大小写敏感不是一回事很多Flink CDC的pipeline配置中会包含schema change相关的设置比如是否将DDL同步到下游。这里要分清楚DDL同步指的是已有表的结构变更比如ALTER TABLE加列schema演进指的是Paimon目标表随之改变结构。两者都不会自动把“新建表”纳入同步除非你的同步工具版本明确支持动态表发现并且你配置了相应的表匹配正则。Paimon catalog本身也有大小写敏感配置。MySQL表名大小写不敏感但Paimon的metastore如果配置为大小写敏感会出现MySQL里的ShopOrder和shoporder被当成两张表的情况或者目标端找不到对应表。整库同步的新表如果建表时大小写风格不一致同步结果会非常随机。3. 实操让新表自动同步的落地路径3.1 先判断该用哪种方案解决运行中新表不同步有几种主流做法各有适用场景。先把方案对比放出来再讲细节。方案优点缺点适用场景重启作业更新表清单操作简单最通用有停机窗口可能要补数新表数量少、允许短时中断使用支持动态发现的CDAS语法新表无需重启自动进入同步需要特定版本配置有要求长期运行的整库同步主链路单独补表作业不影响主作业新表快速上线需要手动维护多个作业只有个别新表不想动主作业定时巡检自动补表完全自动化覆盖面全开发成本高复杂库表数量大、新表频繁的业务从维护成本来看如果一个库每天可能新建多张表重启和补表撑不住如果新表极少拉一套自动化巡检又没必要。实际项目里可以根据新表频率动态选择。3.2 推荐长期方案Flink SQL CDAS整库同步Flink CDC 3.x开始支持通过CDAS语法做整库同步和传统YAML pipeline方式相比它对新建表的处理更友好。一个典型写法是这样的CREATE DATABASE IF NOT EXISTS paimon_shop WITH ( connector paimon, warehouse hdfs:///warehouse/paimon, metastore filesystem ) AS DATABASE mysql_shop WITH ( connector mysql-cdc, hostname 10.0.0.10, port 3306, username cdc_user, password ******, scan.startup.mode initial );这里把MySQL的mysql_shop库整体同步为Paimon的paimon_shop库。在支持的版本下作业运行期间MySQL新建表只要匹配库级范围不需要重启就能被纳入同步。这个方案是我目前在长跑作业里的首选但要注意它对Flink CDC和Paimon的版本兼容性要求比较高落地前一定先查你用的具体版本的官方文档确认动态表发现能力是默认开启还是需要额外参数。3.3 传统YAML pipeline的配置模板如果当前项目还在用YAML pipeline方式配置模板可以这样写source: type: mysql hostname: 10.0.0.10 port: 3306 username: cdc_user password: ****** tables: shop\..* server-id: 5400-5404 scan.startup.mode: initial sink: type: paimon catalog.warehouse: hdfs:///warehouse/paimon catalog.metastore: filesystem catalog.case-sensitive: false pipeline: name: mysql-shop-to-paimon parallelism: 4这个配置里tables用了正则shop\..*匹配整个库。注意server-id: 5400-5404是一段范围的写法给并行子任务分配不同的server-id避免冲突。不过要强调YAML pipeline方式下即使表匹配写的是正则运行中新建表的自动同步能力也取决于Flink CDC版本。老版本即使正则能匹配到作业启动后也不会动态新增表。这个行为的差异比较大必须用你实际版本的文档验证不要想当然。3.4 新表同步后的验证与快速补数不管用哪种方式新表进入同步后都要验证三件事表是否建了、数据有没有在涨、数据是否完整。查表是否存在直接去Paimon的metastore或文件系统里查。如果用的是文件系统metastore最简单的办法hdfs dfs -ls /warehouse/paimon/paimon_shop.db/看有没有新表对应的目录。有表之后等一个checkpoint周期再查数据是否写入SELECT COUNT(*) FROM paimon_shop.user_feedback;如果表和数据都在但怀疑中间有缺失可以参考新表创建时间回查MySQL的binlog位点。通常最省事的办法是单独跑一个只针对新表的补数作业用latest-offset或指定时间位点的模式从头拉一遍保证历史数据不丢。我习惯把这类补数作业设计成一次性作业跑完自动退出不跟主作业长期共存避免双写冲突。3.5 一次完整的实操场景记录举个例子。某天业务在MySQL的shop库里新建了一张user_feedback表业务侧反馈Paimon里查不到这个表。处理过程大概是先确认主作业状态检查Flink UI作业RUNNING无重启记录。接着看日志CDC Source日志中没有关于新表的INFO这基本可以判断新表从未被源端感知。然后查Paimon仓库确认没有对应目录。由于是周末临时需求我选择了最快的方式单独写一个补表作业只同步shop.user_feedback一张表到Paimon指定scan.startup.mode initial让全量快照把所有历史数据先拉一遍之后由它自己的binlog位点继续追增量。同时主作业不重启继续跑原来的表集合。补表作业的SQL大概长这样CREATE TABLE IF NOT EXISTS paimon_shop.user_feedback WITH ( connector paimon, warehouse hdfs:///warehouse/paimon ) AS SELECT * FROM source_mysql_shop_user_feedback;跑完之后业务就能正常查询到数据。当天晚上我再更新了主作业的表清单配置等隔天低峰期重启把这张表并入主链路。这套组合操作不影响业务查询又解决了新表同步的燃眉之急。4. 常见问题与排查技巧实录4.1 典型问题速查表现象可能原因排查方向解决手段新表完全没有建表清单在作业启动时固化新表未被纳入看Source日志是否有新表相关记录更新配置重启或改用CDAS方式新表已建但无数据表匹配成功但数据分发异常或Sink建表后写入失败查Sink日志中的报错信息检查主键配置确认binlog格式新表数据缺一段启动模式或重启导致快照与binlog位点不连续对比源端时间线和目标端数据量单独补数作业回填缺失区间作业RUNNING但没有新表DDL记录MySQL binlog格式不是ROW或权限不足查MySQL变量和CDC账号权限修改MySQL配置补齐权限多作业共享MySQL一实例新表数据乱序server-id冲突检查各作业server-id配置为每个作业分配独立的server-id范围Paimon侧建表一直失败源表无主键Paimon主键策略不匹配看Paimon Sink日志配置合成主键或append-only模式4.2 我的排查顺序与日志定位技巧踩了几次坑之后我总结出一个固定的排查顺序遇到类似问题直接按这个顺序走能省一多半时间。第一先确认作业有没有因为新表DDL而报错或重启。Flink UI上看作业的restart次数如果多次重启问题可能比想象中复杂。第二翻Flink CDC Source的日志搜新表的表名。如果日志里完全没有这个表名说明Source侧就不认识它问题出在上游。如果日志里有DDL相关的记录但之后没有数据记录问题出在数据分发。这一步能快速把问题定位到“源没读到”还是“读了没写”。第三查Paimon的warehouse。看目标目录下有没有对应表目录以及表目录下的文件时间。如果目录存在但文件时间停滞说明数据没进来如果目录不存在说明Sink从未收到该表的数据。第四启用一段时间的binlog监控确认新表在MySQL端的变更是否真的产生了binlog事件。有的MySQL实例因为过滤器配置问题某些库的binlog事件不会完整写入。日志定位的时候不要大海捞针地看全量日志。Flink CDC和Paimon的日志量非常大新表不同步的日志线索往往就那么一两行。优先在TaskManager日志里直接搜表名再结合checkpoint的累计状态去判断有没有数据流过。4.3 规避这个坑的三个工程习惯既然“运行中新表不会自动同步”是很多版本的默认行为与其等技术踩坑不如在系统设计阶段就把问题规避掉。第一个习惯是表命名规范配合动态正则。如果业务上有权限在MySQL建表尽量约定统一前缀比如所有业务表都以shop_开头。这样整库同步的正则匹配范围可以保持稳定后续即使发生增量同步匹配规则也不容易漏。第二个习惯是新表上线后主动触发同步检查。我在运维侧加了一个简单的定时任务每小时扫描MySQL的information_schema把表清单和Paimon的metastore里的表清单做对比出现差异就告警。新表上线后15分钟内没有进入Paimon告警就能打出来不需要等业务方反馈。第三个习惯是重要业务表用独立同步作业。核心大表或者业务方重点关注的表不建议混在整库同步作业里。独立作业的好处是单独一张表的问题不会影响整库出问题时定位和重启也都更灵活。整库同步负责“广覆盖”独立作业负责“关键保障”两者组合比单一整库作业稳得多。我个人现在的习惯是每次业务通知要上线新表我都会顺手在Paimon侧跑一遍验证SQL确认这张表能查到数据才开始对外承诺同步完成。这个操作看起来笨但确实帮我避免过好几次第二天被业务追着问的尴尬场面。整库同步这个领域坑大多不是出在技术难点上而是出在“默认行为”和“用户预期”的错位上。搞清楚哪些是自动的、哪些不是很多问题自然就迎刃而解。