兼容
是对前人努力的尊重
是确保业务平稳过渡的基石
然而
这仅仅是故事的起点

上篇文章聊了KFS的整体架构和目标端入库的优化手段,包括批量提交、小事务合并、Statement缓存、多通道并行和断点续传这些东西。这篇文章终于可以聊到我最想聊的部分了——数据一致性校验和修复。

为什么说这个是"最后一公里"?因为你数据同步得再快、再稳,最后源端和目标端的数据对不上,那前面的一切努力就都白搭了。我见过太多项目,同步工具跑得好好的,大家信心满满准备切流了,结果一做数据比对,发现差了大几百条记录,然后就是无穷无尽的排查和修复,项目延期那是板上钉钉的。

KFS在数据一致性这块确实下了不少功夫,而且我觉得它的设计思路跟其他同步工具有本质区别——不是把校验当作一个附加功能,而是把它作为整个同步架构的核心组成部分来设计的。为什么这么说?因为它不是在同步完了之后才做校验,而是在同步的全生命周期里都贯穿着一致性保障——从初始搬迁阶段的错误处理,到增量同步阶段的实时校验,再到切换前的全面比对,每个阶段都有对应的机制。

数据一致性校验的几种模式

KFS的数据校验一共支持三种模式,从粗到细:

精简模式(Count比对):最简单,就是比对源端和目标端每张表的记录数。这个速度快,但粒度粗,只能发现"多了或少了"的情况。如果一条记录的内容被改错了但数量没变,这种模式就查不出来了。适用场景是日常快速巡检,或者初始搬迁完成后的第一轮验证。

MD5摘要比对:对表中的数据做MD5摘要,然后比对摘要值。这个比纯计数要精确得多,而且性能也还行。KFS支持多线程并行比对,大数据量的场景也能扛得住。适合对精度有一定要求但又不需要逐行查看差异的场景。

详细模式(逐行比对):最精确的方式,逐行比对每个字段的值。能精确到具体哪条记录的哪个字段不一致,连差异的值都能展示出来。但相应的,性能开销也最大。适合上线前的最终验证,或者出了数据不一致问题之后的排查定位。

# 命令行比对工具的用法示例
# 创建一个比对任务
$ cmdcompare create \
    -name check_task_01 \
    -source.host 192.168.1.10 \
    -source.port 18900 \
    -source.service oracle_source \
    -target.host 192.168.1.20 \
    -target.port 18900 \
    -target.service kes_target \
    -conf /opt/kfs/console/conf/table.properties \
    -type all

# 比对类型可选:
# count - 精简模式,只比对记录数
# md5   - MD5摘要比对
# all   - 详细比对(逐行)

# 也可以指定比对策略组合:
# 0: 无策略
# 1: 精简 + MD5
# 2: 精简 + 详细
# 3: 精简 + 详细 + 修复
# 4: MD5 + 详细
# 5: MD5 + 详细 + 修复
$ cmdcompare create ... -ploy 5  # MD5 + 详细 + 自动修复

实际使用中,我一般的建议是分层递进:先用精简模式快速扫一遍,发现数量不对再上详细模式定位具体差异。无缝校验通过特殊的快照机制避免了这种情况。

在线校验——不停业务也能做比对

这个是KFS一个挺重要的能力。很多同步工具做数据比对的时候,需要先把同步链路停掉,然后在一个"静态"的数据快照上做比对。但问题是,生产环境的业务是不能停的啊!你停一个小时的同步来做比对,万一这段时间源端有新数据进来怎么办?数据就更不一致了。

KFS的在线校验就解决了这个问题。它可以在同步链路正常运行的同时,对源端和目标端的数据进行比对。这背后其实有不少技术挑战的:

首先,同步链路在持续写入目标端,你在比对的同时数据还在变化,怎么保证比对结果的准确性?KFS的做法是通过数据库的快照隔离机制,在比对开始时获取一个一致性快照,然后在快照的基础上做比对。这样即使目标端还在持续写入,比对看到的也是某一个时间点的一致性状态。

其次,在线比对不能影响源端业务。KFS的校验查询走的是只读查询,而且通过fetchSize参数控制每次读取的记录数,避免一次性加载大量数据到内存里造成OOM。

# 校验配置参数(console/conf/下的配置文件)
# 任务并行数:同时能执行多少个校验任务,范围1~5
task.parallel.count=2

# 校验核心线程数:同时有多少张表在并行比对
# 建议设置为CPU核心线程数,提升并行度
task.pool.corePoolSize=8
task.pool.maxPoolSize=8

# 校验查询fetchSize:每批次读取的记录数,范围1~100000
# 太小了频繁查询网络开销大,太大了内存吃不消
compare.fetchSize=10000

# 校验同步fetchSize:获取差异数据的批次大小
compare.sync.fetchSize=5000

# 批量修复大小:修复时批量入库的大小
repair.batchSize=500

# 校验同步是否记录日志(是否会被再次作为增量解析)
compare.sync.log.enabled=true

# 校验结果自动清除天数(每日0点自动清除N天前的结果)
compare.result.autoClean.days=7

# 是否校验大对象字段(BLOB/CLOB等)
compare.lob.enabled=true

# 大对象校验阈值(字节),超过此长度用特殊字符串代替
compare.lob.threshold=5000000

# 修复时是否跳过超阈值的大对象
compare.lob.skipOnSync=true

关于校验线程数的配置,有个小技巧。你可以用这个命令看CPU核心线程数:

# 查看CPU核心线程数
$ lscpu | grep "Thread(s) per core"
Thread(s) per core:    2

$ grep 'processor' /proc/cpuinfo | sort -u | wc -l
16

# 核心线程数 = CPU数 × Thread(s) per core
# 或者直接:
$ cat /proc/cpuinfo | grep processor | wc -l
16

把校验核心线程数设到跟CPU核心线程数一样大,再配合调大比对程序的内存(默认4GB,可以改到8GB甚至更高),比对速度能提升不少。特别是表特别多的场景,多线程并行比对的效果很明显。

# 修改比对程序内存
# 编辑 compare/conf/wrapper.conf
wrapper.java.maxmemory=8192  # 默认4096,改成8GB

全周期一致性校验是怎么做到的

这里要展开说说KFS所谓的"全周期"到底是什么意思。按照我的理解,它覆盖了三个阶段:

阶段一:初始搬迁阶段的数据校验

用KFS做数据初始搬迁的时候(就是从源端把存量数据全量搬到目标端),KFS会统计和展现以下信息:搬迁模式及表信息、源表数据条目数、搬迁结果状态、异常错误信息,便于用户在搬迁结束后复盘。

而且KFS有个不错的容错设计:搬迁过程中如果遇到错误,支持忽略错误继续搬迁,同时把出错的数据单独保存起来,后续可以做二次搬迁。这个在实际项目里很有用,因为源端数据难免有些脏数据或者格式不兼容的情况,你不能因为一条数据有问题就停住整个搬迁流程。

搬迁完成之后,你可以直接发起一次精简模式的数据比对,快速确认两端的记录数是否一致。如果有差异,再用详细模式定位具体的差异记录。

阶段二:增量同步过程中的定期校验

数据进入增量同步阶段之后,KFS支持按需启动比对任务,包括三种触发方式:

  • 立即比对:手动触发一次,适合临时需要验证的场景
  • 定时一次性比对:在指定时间执行一次,适合在业务低峰期做验证
  • 周期性比对:按照设定的时间周期反复执行,适合长期运行中的持续监控
调度管理配置示意:
┌──────────────────────────────────────┐
│  调度任务名称:每日凌晨数据校验        │
│  执行任务:                           │
│    [x] 订单表比对                     │
│    [x] 用户表比对                     │
│    [x] 支付流水表比对                  │
│    [ ] 操作日志表比对(非核心,跳过)    │
│  调度策略:每天                       │
│  执行时间:02:00                      │
│  状态:● 生效                        │
│  [立即执行]  [启用/停用]  [编辑]      │
└──────────────────────────────────────┘

我建议是设置一个每天凌晨的定时比对任务,把核心业务表都加上。凌晨业务量最小,比对操作对系统的影响也最小。对于特别核心、数据量特别大的表,可以一天比对多次。非核心的表可以一周比对一次就够了。

阶段三:切换前的最终校验

当你要做业务切换(比如从Oracle切到KingbaseES)之前,需要做一次最终的全面数据校验。KFS的详细模式可以逐行比对每个字段的值,确保数据完全一致之后再切流。

切换的一般步骤是:

  1. 停用源端的业务系统
  2. 用KFS做最后一次数据验证(建议用详细模式)
  3. 确认数据一致后,启动目标端的业务系统

如果用了双轨并行方案,切换之前可以一直保持KFS的双向同步,两端数据实时一致,什么时候觉得没问题了什么时候切。而且如果切过去之后发现问题,还可以切回来——因为源端一直在跑,KFS也在持续同步,随时可以回退。

自动修复——从"被动发现"到"主动治理"

发现了数据不一致,接下来就是修复。这个环节KFS也做了不少文章。

手动修复有几种方式:

  • 整表修复:把某张表的所有差异数据一次性同步过去
  • 批量修复:当前页所有差异表批量处理
  • 行级修复:选择特定的差异记录进行修复
  • 按类型修复:按INSERT/UPDATE/DELETE分类修复
数据比对结果界面示意:
┌─────────────────────────────────────────────────────────────┐
│  表名          │ 源端行数  │ 目标端行数 │ 差异数 │ 操作     │
├────────────────┼──────────┼───────────┼───────┼──────────┤
│ orders         │ 1500000  │ 1500000   │  0    │  一致 ✓  │
│ order_items    │ 4500000  │ 4499857   │ 143   │  ▶同步   │
│ user_info      │  800000  │  799999   │  1    │  ▶同步   │
│ payment_log    │ 2000000  │ 1999998   │  2    │  ▶同步   │
│ sys_config     │    200   │    200    │  0    │  一致 ✓  │
└─────────────────────────────────────────────────────────────┘

点击"同步"之后,展开差异明细:
┌─────────────────────────────────────────────────────────────┐
│  差异明细 - order_items                                      │
├─────────────────────────────────────────────────────────────┤
│  差异类型 │ 主键ID  │ 差异字段    │ 源端值    │ 目标端值   │
│  UPDATE  │ 100234 │ amount    │ 150.00   │ 120.00     │
│  INSERT  │ 100235 │ (整行)    │ {...}    │ 缺失       │
│  DELETE  │ 100236 │ (整行)    │ 缺失     │ {...}      │
│  UPDATE  │ 100237 │ status    │ PAID     │ PENDING    │
│                                                           │
│  [✓全选]  [批量更新] [批量增加] [批量删除]  [开始同步]      │
└─────────────────────────────────────────────────────────────┘

这里有个细节值得说一下:修复操作本身会不会被增量同步再次捕获,导致无限循环?答案是不会的。KFS通过一个配置项compare.sync.log.enabled来控制校验同步操作是否记录事务日志。如果设为true,修复操作会被记录并同步到源端(适用于双向同步场景);设为false则不会。

自动修复是更高级的功能。你可以创建一个修复任务,绑定到某个比对任务上,设定触发条件:

自动修复任务配置:
┌──────────────────────────────────────┐
│  修复任务名称:订单表自动修复          │
│  匹配比对任务:订单表详细比对          │
│  修复等待时间:60 秒                  │
│  修复启动阈值:差异条数 >= 10 条      │
│  触发方式:比对完成后自动执行          │
│                                      │
│  不同表可设不同阈值:                  │
│  order_items: >= 5 条                │
│  user_info:   >= 1 条                │
│  payment_log: >= 3 条                │
└──────────────────────────────────────┘

当比对任务完成之后,如果发现的差异条数达到了你设定的阈值,KFS就会自动启动修复流程,把差异数据同步过去。整个过程不需要人工干预。修复完成后,管控台会展示修复结果,包括每个表的修复状态和修复详情。

当然,自动修复这个功能得谨慎使用。我的建议是,在双轨并行初期,先用手动修复,确认每次修复的结果都是符合预期的。跑了一段时间之后,如果觉得差异的类型和原因都比较稳定了,再开启自动修复。另外修复启动阈值不要设太低——因为同步过程中由于时序问题,可能会出现短暂的"假不一致",等增量追上来就自动一致了。阈值太低会导致自动修复频繁触发。

告警机制——出事了第一时间知道

KFS在校验过程中发现数据不一致的时候,不会只是默默记个日志就完了。它支持通过多种方式告警:

  • 邮件通知
  • 短信通知
  • 微信告警
  • 钉钉告警

这个在实际运维中很重要。你不可能24小时盯着管控台看,但只要配置了告警,数据出了问题就能第一时间收到通知。

管控台本身也提供了很完善的监控统计功能:按同步链路、按同步节点,实时展示同步数据量、同步延迟、同步速率等关键指标。还有表级的同步操作分析和性能耗时分析,哪张表同步慢了、卡在哪一步了,一目了然。当某条链路延迟突增,系统能迅速定位到具体瓶颈节点,将故障排查时间从小时级缩短至分钟级。

# 通过API检查同步状态(KFS支持RESTful API)
$ curl -s http://localhost:8080/api/v1/services/oracle_source/status \
    | python3 -m json.tool
{
    "serviceName": "oracle_source",
    "state": "ONLINE",
    "appliedLastSeqno": 158723,
    "appliedLatency": 0.152,
    "role": "master",
    "extractorLag": 0.003,
    "applierLag": 0.149
}

# 检查数据校验结果
$ curl -s http://localhost:8089/api/v1/compare/results/task_001 \
    | python3 -m json.tool
{
    "taskName": "daily_check",
    "status": "COMPLETED",
    "tablesChecked": 45,
    "tablesMismatch": 2,
    "totalDiffs": 15,
    "autoRepaired": 12,
    "pendingRepair": 3
}

几个真实案例中的数据一致性实战

说了这么多技术细节,来讲几个实际项目里KFS是怎么保障数据一致性的。这些案例都来自KFS的产品资料和技术文档,有些是我自己参与过的,有些是同行的经验分享。

案例一:解放军总医院——超大规模数据汇聚

这个项目是把解放军总医院下属8个医学中心(一、三、四、五、六、七、八医学中心以及京东医疗区)的医信系统数据归集到DWS数仓,用于数据分析治理。涉及的源库包括Oracle 11gR2/19c、SQL Server 08/08r2/12/16、MySQL 5.7/8.0、KingbaseES V8等,操作系统横跨Windows、Linux、AIX、Solaris,存量数据60TB+,日增数据300GB+,涉及HIS系统、LIS检验、电子病历、急诊、康复、护理、超声、心电等多个关键业务。

每个医学中心部署2节点KFS前置机,实时采集业务数据后经过清洗、转换再合并入湖。这个场景的复杂度在于:400多个业务系统、多种异构数据源、跨多个院区。

KFS在这个项目里的数据一致性保障方案是:采集转换延时控制在10秒以内,数据一致性定时校验,事务序列实时保障,以及多维容错机制——软件故障自动重试,网络中断断点续传。60TB的数据量级,还能保持这个一致性水平,确实不容易。

案例二:北京市政一卡通——12.3TB数据的平滑迁移

北京市政一卡通这个案子,承载1.8亿用户量,12.3TB的存量数据,早高峰三小时5900万笔交易,TPS峰值2000笔/秒,不允许业务停机。需要从Oracle 12C RAC(2+2同城容灾+1读节点)迁移到KES读写分离集群。

用KFS做增量数据同步。迁移过程中,每天500G的增量数据要秒级同步。数据一致性方面,KFS提供了不停机的自动比对和修复功能。

最终结果:存量12.3TB迁移耗时不到3天,每天500G增量秒级同步,早高峰3小时支撑5900万笔交易,单表超亿行数据,容灾故障秒级切换。晚间2小时批处理事务126万个。这个数据量级和性能指标,说实话还是挺 impressive 的。

案例三:中国人民银行征信中心——跨1000KM的双中心双活

这个案子更极端。原系统是IBM小机2节点+Oracle RAC,数据量300GB;容灾中心用海光芯片+3节点KES集群,两个中心之间距离超过1000公里。用KFS做双链路实时同步+高可用分离部署。

用户最担心三件事:有没有成熟的异地容灾产品、网络不稳定性能否保障、异构数据库存储精度是否一致。

KFS的方案是:断点续传+传输压缩,在低带宽高时延环境下实现跨地域准实时同步。数据一致性方面,KES在存储精度和数据类型上完全对标Oracle(这也是个关键点——目标端数据库本身的数据类型精度要跟源端一致,不然同步工具再怎么校验也没用),再加上KFS的全自动在线数据校验和修复,最终做到了延迟小于1秒的双中心双活。还支持异构双中心定期切换,一键切换应用无修改。

案例四:某直辖市法院——112个数据源的大集中

全市206个子系统的信息化改造,涵盖审判系统、执行系统、司法管理系统、诉讼服务系统、保障系统5大类。112个同步数据源、77条同步链路。原来是20多节点Oracle RAC加80节点Oracle单机,新系统换成鲲鹏920+麒麟V10+KES集群。

KFS在这个项目里替代了原有的DB-LINK方案。5个业务库加1个汇总库,共6个数据库集群支撑全市法院的所有核心业务。3000多个存储过程、500多个复杂视图、500多个复杂SQL,全量业务迁移上云。

这种规模的同步链路,数据一致性校验的压力是很大的。KFS的统一管控台在这里发挥了关键作用——在一个界面里管理77条同步链路的状态,按链路做表级同步操作分析和性能耗时分析。而且因为是全信创环境(鲲鹏+麒麟+KES),对同步工具本身的信创兼容性也有很高要求。

案例五:嘉实基金——60TB的TA系统迁移

金融行业的核心系统,60TB存量数据,每天1500万笔事务的跑批业务,不允许停机。从Oracle RAC迁移到KES集群(鲲鹏+麒麟V10)。

这个项目的数据一致性要求极高——金融数据差一分钱都不行。KFS提供了表级的不停机数据一致性实时自动比对与修复,业务切换时长控制在30分钟以内,跑批业务延时也控制在30分钟以内,日常业务延时小于1秒。60TB的存量数据无感平滑迁移,这个体量在金融行业里也算大型项目了。

一些实操建议和踩坑记录

最后分享一些我在实际使用中的经验教训,给大家避避坑。

1. 跨广域网场景下的比对优化

如果源端和目标端之间网络带宽比较低(比如只有2M),做详细比对会很慢,因为需要大量跨网络查询数据。这时候建议用精简模式或者MD5模式,减少跨网络的数据传输量。KFS的广域网传输优化技术有4倍的压缩比,2M带宽就能支撑实时容灾同步。但比对毕竟是额外的查询操作,在低带宽环境下还是要控制频率。

2. 命令行工具是无GUI环境的救星

有些生产环境(比如涉密网络或者安全管控严格的环境)不允许部署图形化工具,这时候KFS的命令行比对工具(cmdcompare)就很有用了。功能跟Web界面是一样的,只是操作方式不同。

# 创建比对任务并立即执行
$ cmdcompare create \
    -name prod_check_$(date +%Y%m%d) \
    -source.host 10.0.1.10 \
    -source.port 18900 \
    -source.service oracle_prod \
    -target.host 10.0.2.10 \
    -target.port 18900 \
    -target.service kes_prod \
    -conf /opt/kfs/console/conf/table.properties \
    -type all \
    -ploy 3   # 精简+详细+修复

# 仅创建任务不执行
$ cmdcompare create ... --create-only

# 运行已有的比对任务
$ cmdcompare run -name prod_check_20260831

# 查看比对结果
$ cmdcompare result -name prod_check_20260831

# 全局参数:
# -port 8089        控制台端口(默认8089)
# -username admin   控制台用户名
# -password admin   控制台密码

3. 双向同步场景下要注意防回环

如果你做了双向同步(A→B和B→A),一定要注意KFS的防回环机制。特别是数据校验修复这块,在业界同类产品中确实算做得比较深入的。

从产品演进来看,KFS从2009年的前身KingbaseSS V7.0开始,到2017年正式以KingbaseFlySync品牌发布,再到现在的V2 R6版本,经历了十几年的迭代。从最初只支持Oracle数据源,到现在支持30多种数据源;从简单的1对1同步,到支持1对多、多对1、级联、双向等复杂拓扑;从手动数据比对,到全自动在线校验和修复——这个演进过程本身也说明了这个产品在持续进化。

当然它也不是完美的。比如对某些小众数据源的支持还不够成熟,文档也有待完善(有些配置项的说明不够详细,得去翻源码或者问技术支持),管控台的UI设计也有改进空间。但总的来说,在国产异构数据同步工具里,KFS目前算是走得比较靠前的一个。特别是配合KingbaseES的深度适配(毕竟是自家产品),在信创场景下的整体体验是比较好的。

好了,就写到这里。如果对KFS还有什么想了解的,或者在数据同步方面有什么坑想讨论的,欢迎留言交流。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐