做异构数据同步的时候,最容易被低估的是什么?其实不是网络带宽,也不是第一次全量迁移的速度,而是迁移完成之后,怎么去证明两边的数据还是一致的。要知道,源库还在继续接收交易,目标库也在不停地回放增量。那校验如果只在业务停机窗口里做一次的话,结果往往仅仅只能说明"某个时间点看起来是一致的"而已。真正能让人放心的东西是什么呢?是业务继续跑着的同时,存量和增量都能被持续检查,发现差异了还能定位到具体的记录,然后修掉。
这也是我在梳理金仓异构数据同步软件 KFS 的时候,最关注的一条主线:异构数据同步这件事,不是简单地把 INSERT、UPDATE、DELETE 扔到另一端就完事了,而是要把采集、传输、加载、校验和恢复这些环节,连成一个可追溯的闭环。 
@toc
一致性为什么会在迁移后失效
全量数据迁移结束了,是不是就代表迁移真正完成了呢?不代表。常见的双轨运行场景是这样的:源端继续承载业务,目标端通过日志解析不停地往前追。那这个阶段至少有三类风险:
- 全量阶段某些大表或者热点表没搬完整,目标端就已经开始接收增量的数据了;
- 增量链路上发生了网络抖动、进程重启,或者归档日志切换的情况,造成了局部积压;
- 两端的字符集、时间类型、数值精度或者默认值,处理方式不一样,数据虽然"同步成功"了,但落地结果并不完全相同。
那如果只比较两边的总行数行不行呢?不行。因为删除、重复写入、还有同一主键内容被修改的情况,用总行数是识别不出来的。所以可靠的校验至少要能回答三个问题:哪张表有差异、差异落在了哪些记录上、修复之后还能不能再次通过校验。
KFS 的同步链路应该怎样理解
从技术链路的角度看,KFS 可以拆成采集、跟踪文件、传输转换和加载这么几个环节。采集端去读源数据库的物理日志,把变更事件写进中间文件;然后加载端呢,再按照源端事务提交的顺序,把这些事件转换成目标数据库能执行的 SQL。这样的设计有两个直接的好处:
- 源端不需要为了同步工具额外去维护一套业务表,采集对生产库的干扰比较小;
- 源端或者目标端暂时不可用的时候,已经采集的变更仍然保留在跟踪文件里,恢复之后可以从断点接着走。

事务顺序这个东西,是整个链路里的关键。举个例子,一个业务事务可能同时改了订单、库存和流水这三张表。那如果只保证单条记录能到,却没有保持事务边界和提交顺序,会发生什么呢?目标端可能先看到库存扣减了,后面才看到订单生成,短时间内就会出现引用关系不完整的情况。KFS 的加载过程呢,是以事务为单位来回放的,并且会持续记录位点,这样就不会把一个完整的事务拆成那种没法恢复的半成品。
全周期校验:存量和增量要分开看
我更愿意把 KFS 的一致性能力,理解成两个并行的校验周期。 
存量数据校验
存量校验要解决的问题,是"全量搬迁到底完不完整"。可以按表执行全量的详细比对,也可以根据数据规模,选择抽样比对、摘要比对或者过滤比对。那大表直接逐行去比会有什么问题呢?网络和 I/O 的成本会非常高。所以摘要方式的话,通常是在两端按主键范围或者分片先算好 MD5 这类摘要,然后只对摘要不一致的范围做记录级的定位。
示意流程是这样的:
text
源端快照/分片读取
|
v
按主键范围计算摘要 ---> 目标端按同一范围计算摘要
| |
+------ 摘要一致 ----------+----> 通过
|
摘要不一致
v
进入记录级差异清单
这种方式的价值在哪里呢?不在于"把比对做得更复杂",而在于把昂贵的逐行检查,集中到真正可疑的范围内。公开资料里给出的典型能力是这样的:100GB 级的数据,平均可以在分钟级完成校验,平均在线校验速率大概 100MB/s。当然要注意,这个数字是取决于硬件、网络、表结构还有校验策略的,不能直接当成所有项目的承诺。但是它至少能说明一件事:校验模块并不是只能在停机窗口里跑的。
增量数据校验
增量校验解决的是另一个问题,就是"同步过程中有没有悄悄跑偏"。它不需要把业务停下来,也不必反复去查询正在承载交易的源库。那 KFS 是怎么做的呢?它会利用同步链路里已经捕获到的变化数据,在源端和目标端分别形成可以比对的快照,然后针对发生变化的范围去做校验。这样做的好处是什么呢?校验任务和同步传输链路是相对独立的,不会因为一次全库扫描,就把同步延迟给推高了。
在一个典型的双轨迁移里,我会按下面的顺序来安排校验:
- 全量迁移完成之后,先执行一次存量摘要比对,确认大范围的数据没有漏迁;
- 增量追平期间,按业务表或者时间窗口去执行增量比对;
- 切换之前,对核心表做一次记录级的复核;
- 切换之后呢,继续保留周期校验,一直到旧库正式退出为止。
这样的安排,避免了"到切换前才发现有差异"的被动局面。而且还有一个好处,差异能和具体的同步阶段对应起来,方便排查。
发现差异后,修复才是闭环
校验工具如果只是把差异报出来,运维人员还是得停下来自己分析,那价值就会打折扣。KFS 的处理方式呢,是先生成差异清单,然后支持两种修复路径:一种是少量的关键记录,手动修正;另一种是确认可以按源端结果覆盖的差异,走自动修复。
要注意的是,记录级修复必须尊重主键和事务顺序。拿订单表举例,不能只把目标端某一列改成源端的值就完事,还要判断这条记录在源端到底是新增、更新还是删除。一个更稳妥一点的伪 SQL 是这样:
sql
-- 仅用于说明修复逻辑,实际语句由同步工具按源端事件生成
MERGE INTO target_order t
USING repair_order_delta s
ON (t.order_id = s.order_id)
WHEN MATCHED AND s.change_type = 'U' THEN
UPDATE SET amount = s.amount, status = s.status
WHEN MATCHED AND s.change_type = 'D' THEN
DELETE
WHEN NOT MATCHED AND s.change_type = 'I' THEN
INSERT (order_id, amount, status)
VALUES (s.order_id, s.amount, s.status);
那真正上线的时候呢,还要考虑外键依赖、触发器、审计字段还有业务时间戳这些东西。所以说,自动修复是不能脱离规则配置单独跑的。比较好的实践是什么呢?先让工具输出差异明细和修复范围,由 DBA 审核过了之后,再开启全自动模式。已经验证过的标准表的话,就可以交给无人值守任务去处理了。
"0 停机"不是一句口号,而是一条迁移路径
KFS 的平滑迁移,通常来说不是把所有步骤压缩到一次窗口里,而是把迁移拆成四段:结构迁移、存量搬迁、增量同步、业务切换。存量搬迁可以慢慢来,源端继续提供服务,不受影响;搬迁期间产生的日志呢,被持续地解析并缓存起来;存量结束了,增量再按位点追平;那到切换的时候,只需要处理最后那点延迟,加上连接切换就行了。
这种方式的本质是什么呢?就是把"停机等全量复制"变成"在线复制加短时切换"。公开案例里有一个项目,12.3TB 的存量数据,每天大约 500GB 的增量,用的是并行迁移加实时校验,存量迁移耗时不到 3 天,切换前还能执行不停机的数据比对和修复。当然要说一句啊,案例数字是特定环境下跑出来的结果。真正做方案设计的时候,还是要按源端日志量、目标端写入能力和网络条件重新核算一遍的。
源端影响如何控制
数据同步工具最常见的一个担忧是什么?"为了做校验,反而把生产库拖慢了"。KFS 的思路呢,是尽量去依赖日志和快照,而不是对源库做大范围的业务查询;同时把采集、解析、加载和校验拆成独立的阶段。资料里给了一个项目的观测数据:校验的时候,业务机 CPU 负载的增加小于 3%。那这个数字怎么用呢?我会把它当作方案设计时的参考边界,而不是脱离环境直接照抄的指标。
更可操作的控制手段,其实有这么几个:
- 把全量摘要任务放在业务低峰期跑,增量校验按表分批执行;
- 先校验核心表,然后再逐步扩大范围;
- 给校验线程设置上限,避免和日志解析去抢 CPU;
- 把差异清单、修复记录和位点一起保留下来,方便回溯。
我对这套方案的判断
异构数据同步真正需要建立的东西,是一条"数据无忧"的证据链:源端日志能连续读取,事务能按顺序落地,存量和增量都有校验,差异能定位并且修掉,进程或者网络出了故障之后,还能从位点继续。KFS 的优势呢,不只是支持多种数据源,而是把这些步骤放进了同一套同步和管控流程里。
那它是不是项目管理的万能开关呢?不是。字符集转换、业务规则映射、不可逆的数据清洗,这些还是要在迁移前就明确清楚的。自动修复也必须建立在主键、外键和业务语义都确认过的基础上。对我来说,判断一套异构数据同步方案可不可靠,最后看的不是宣传页上的峰值数字,而是它能不能回答这三个问题:差异在哪里、为什么发生、修复之后怎么证明已经恢复了。
保留的运维记录
为了让校验结果在切换评审的时候真正有用,我会把每次任务的范围、位点和结果都保存下来,而不是只截一张"任务成功"的界面图。至少要保留下面这些信息:
- 校验开始和结束的时间,还有对应的源端、目标端位点;
- 参与校验的表清单、过滤条件和摘要算法;
- 差异记录的主键、差异类型和修复批次;
- 修复前后的再次校验结果;
- 任务期间的同步延迟、源端 CPU 还有目标端写入队列的变化。

为什么要留这些呢?因为它能帮你区分两种情况:一种是"源端后来又发生了更新",另一种是"同步链路真的丢了一条记录"。这两个问题性质完全不同。没有位点和时间窗口的话,单纯看到两边的数值不一样,你很难判断问题到底是出在迁移、同步,还是业务本身。
另外还有一点,自动修复应该设置熔断条件。比如连续差异的数量超过了阈值、主键冲突比例异常,或者目标端延迟一直在升高,这些情况出现了,就先暂停自动修复,把现场保留下来。这样做的好处有两个:一是避免错误数据被大面积覆盖,二是给 DBA 留出分析的时间。KFS 提供了自动和手动两种修复路径,那怎么组合呢?还是应该由业务表的重要程度和风险等级来决定。