前言
把一个跑了十年的Oracle核心库换成金仓数据库,中间隔着什么?
我给你数数:十几个TB的存量,每天几百GB的增量,7×24小时不能停的业务——对了,还有审计部门那句能把人问住的灵魂拷问:"切完之后,你怎么证明两边数据一条不差?"
行吧。做过异构数据同步的都懂,链路搭起来真只是万里长征第一步。真正让人半夜睡不踏实的,从来不是延迟高了两秒,而是那种"面板上一切正常,数据其实早对不上了"的情况。等对账对出问题再去找,黄花菜都凉了。
金仓的KFS(Kingbase FlySync,金仓异构数据同步软件)在这块儿下的功夫挺对路子:低侵入高性能的同步架构、内置的全周期数据一致性校验、0停机平滑迁移,再加一堆行业核心案例。这篇文章我就顺着"数据一致性"这条线,把它扒开看看。
@TOC
一、先想清楚:数据是从哪儿开始对不上的
聊工具之前,咱先把伤口亮出来。不一致的口子,我这些年见来见去,翻来覆去就那么几个。
全量和增量的接缝。 存量搬完那一秒,业务还在往里写呢。接缝处的SCN/LSN要是没对齐,得,丢数据就从这一刻开始,而且丢得悄无声息。
故障重传。 网络闪一下、进程崩一下,太正常了。重传少了丢数据,重传多了出重复,两头堵。
大事务回放。 源端一个几十万行的大事务,目标端回放到一半挂了——这算同步成功还是失败?你说尴尬不尴尬。
类型映射。 数值精度差一位、时间戳毫秒位没保住、字符集转岔了,任何一处小偏差,都是"看起来同步了,一对账懵了"。
人。 对,就是人。有人在目标端直接改了条数据做测试,改完忘了还原。别笑,这种事故我听得耳朵起茧,比你想象的多得多。
前四条,靠同步软件自己的工程质量去堵。第五条呢?软件管不了人,只能靠校验把问题揪出来。所以我说,同步和校验压根是两码事——同步负责"尽量对",校验负责"证明对"。市面上大部分工具,光顾着前面那半句了。
选型的时候,路子无非这几条,我直接摊开说:
| 同步路线 | 怎么干的 | 实时性 | 对源端的侵入 | 一致性上的坑 |
|---|---|---|---|---|
| 应用双写 | 业务代码同时写两个库 | 准实时 | 高,得改代码 | 任一端写失败就分叉,跨库事务基本没辙 |
| 定时ETL批量 | 按时间窗口抽数 | 分钟到小时级 | 中,扫描压力大 | 窗口内数据还在变,天生滞后 |
| 触发器/日志表 | 库内埋点记变更 | 秒级 | 高,每个事务多一跳 | 写放大,高峰期容易把业务库拖趴下 |
| 日志解析CDC | 解析数据库事务日志 | 秒级甚至亚秒 | 低 | 链路环节多,更得有校验兜底 |
不用绕弯子,日志解析CDC就是当下的主流,KFS走的也是这条路,对标OGG那批老牌工具。但它比别家多想了一步:把校验和修复直接塞进产品里了。这也是我今天最想展开讲的部分。
二、链路长啥样:数据是怎么搬过去的
KFS的链路就三段:采集、KUFL、加载。一段段说。
采集端不搞虚的,直接读数据库的事务日志(Oracle的Redo就是典型),把INSERT、UPDATE、DELETE的最终结果解析出来。这里有个细节我特别想提一嘴:它只解析已提交的事务,没提交的中间状态、回滚操作,统统跳过。别小看这一点——日志解析量下来了,脏数据从源头就掐没了,一举两得。
中间那层叫KUFL,全称Kingbase Unified Format Log。各家数据库的日志格式差得十万八千里,KFS采集完统一封装成加密的KUFL格式再传,事务的提交顺序、ACID属性,原样躺在文件里。这设计还有个白送的好处:源端或目标端随便哪边断了,KUFL里存着断点前的最新数据,恢复了接着传就完事,不用从头再来。断点续传的底气,就搁这儿了。
加载端从KUFL里读数据,转成目标库的原生SQL,严格按源端的提交顺序入库。目标端只要能走JDBC就能加载——这也是它能对接的目标源那么杂的原因。金仓数据库KingbaseES自然不在话下,Oracle、MySQL、SQL Server、DB2、达梦、OceanBase、Gbase、openGauss这些关系库都行,往Kafka、Greenplum、ClickHouse、Hive、华为DWS这类数仓和大数据平台落也没问题。拓扑就更随意了,一对一、一对多、多对一、级联、双向随便组,跨网段、跨隔离装置的网络照样跑。
链路跑起来之后,还有三道检查在后头盯着:事务顺序(源端什么顺序,目标端就什么顺序加载)、日志连续性(序号不能断)、持久化I/O顺序。哪道对不上,链路直接拦下来报错,绝不默默吞掉。我个人很喜欢这个设计——报错不可怕,闷声吞数据才可怕。
"低侵入"这事儿多说两句。KFS不在业务库上建触发器、不加辅助表,解析的活儿全搬到自己节点上干,对生产库的开销基本就是读归档日志那点I/O。某市中心医院的迁移项目实测过:KFS进程内存稳定在1.8~1.9GB,CPU单核占用不到70%。在生产环境上过手的都知道这意味着什么——基本可以无视。
性能甩一组官方数(X86六核16G、SSD、千兆网的环境):Oracle源端解析118MB/s,KES源端101MB/s,目标端加载240MB+/s,端到端时延40ms。局域网TPCC模型下比业界同类高30%左右;广域网有4倍压缩传输,2M带宽就能撑起实时容灾——2M啊,也就家里宽带的零头,这都能容灾。
加载端为啥快?说白了就两招:攒批,加预编译复用。核心逻辑简化掉细节,长这样:
// KFS目标端回放的核心套路(简化示意):攒批 + 预编译复用
PreparedStatement ps = stmtCache.getOrPrepare(sqlTemplate); // 相同SQL模板只解析一次
for (RowChangeEvent row : events) {
ps.setObject(1, row.col(0));
ps.setObject(2, row.col(1)); // 只重绑参数,解析那步全省了
ps.addBatch(); // 先攒着,不急着发
if (batchFull() || tableChanged()) {
ps.executeBatch(); // 一口气刷给目标库,网络往返从N次降到1次
}
}
conn.commit();
checkpoint.persist(seqno); // 提交成功才落断点,崩了就从这儿续
这笔账闭着眼都能算:逐条执行,一条SQL一趟网络往返;攒批之后,一批一趟。SQL模板还只解析一次。碰上跑批那种几十万行的大事务,KFS还有大事务分片、多通道并行入库的手段——按表拆,狠起来按行哈希拆。这块展开能讲一万字,先按住不表。
三、重点来了:全周期一致性校验,不停业务的那种
先说说土办法有多难受,你们感受一下。
要校验两边一张表是否一致,最直接的就是两边各算一遍行数加聚合值,再比对。源端是Oracle的话,大概这么写:
-- 源端:把关键列拼起来算摘要,大表跑一次几十分钟起步
SELECT COUNT(*) AS row_cnt,
SUM(ORA_HASH(id || '|' || amount || '|'
|| TO_CHAR(upd_time, 'YYYY-MM-DD HH24:MI:SS.FF6'))) AS chk_sum
FROM finance.settle_detail
WHERE upd_time >= TRUNC(SYSDATE); -- 想只比增量?时间戳自己维护去
然后目标端还得再写一份等价的。函数名不一样,时间格式不一样,时区差一毫秒,摘要立马对不上。对不上的时候你根本分不清:是数据真丢了,还是SQL写岔了?更狠的是,这种查询赶在业务高峰扫大表,源端直接被扫到报警。于是大家只好排到凌晨两三点的"业务低峰期"去跑。
听着挺合理对吧?问题是有系统压根没有低峰期。301医院(解放军总医院)的数据汇聚项目就卡在这儿——8个院区、400多个业务系统、60多TB存量、每天300GB往上的增量,医疗业务全天候转,你跟我说哪个小时是低峰?凌晨三点急诊科可不这么认为。
KFS的思路是真换了个角度:校验压根不去"查"源端业务库,而是把同步链路本来就拿到的数据复用起来。拆开就两层。
存量校验,靠快照。源端目标端各拍一份快照,俩静态视图搁那儿比,业务该写写该读读,完全不耽误。你肯定要问:快照怎么保证两边是同一个逻辑时点?问得好。源端事务解析的时候带编号,快照和编号做映射;目标端装载到对应编号的事务时,暂停装载、取快照。这么一来,两边比的就是同一瞬间的数据,没得耍赖。
增量校验,靠KUFL。同步链路本来就把增量变更存在KUFL文件里了对吧?校验模块直接从KUFL里捞指定时间段变化的数据,搁进内存哈希表,再去目标端查对应记录核对。全程不碰源端数据库,源端零压力。这是整个方案里我认为设计得最漂亮的一笔,等于把同步链路的劳动成果白嫖了个遍(褒义)。
范围和效率上,给了几种打法按需组合:
| 校验方式 | 怎么干的 | 适合啥场景 |
|---|---|---|
| 全量详细比对 | 两端快照后逐行核对 | 上线前的最终确认 |
| 筛选过滤比对 | 只比指定的模式、表、字段 | 核心账务表重点盯防 |
| 抽样比对 | 按比例抽数据行 | 超大表的日常巡检 |
| MD5摘要比对 | 列值拼起来算摘要再比 | 大宽表,省传输省比对量 |
| 多线程比对 | 多表并发校验 | 压缩整体校验窗口 |
效果直接上数,不整虚的。100GB数据的平均校验时间,分钟级;在线校验速率100MB/s上下。侵入性有两组实测摆这儿:301医院项目,校验速率98MB/s,校验期间业务机CPU负载增加不到3%、内存加4G以内,校验准确性100%;人行征信中心那个项目,存量4TB+、日增50GB+,以前全表校验一遍6小时起步,改成基于KUFL的增量校验,10分钟内跑完,CPU负载增加照样压在3%以内。还有中汇亿达的金融项目,2TB数据1小时比完,约25万行每秒。
CPU增加不到3%是什么概念?跑校验的时候你去业务机上top一眼,基本看不出它在干活。
哦对,还有个容易漏掉的点:校验链路和同步传输链路是分开的。开校验不拖累同步,同步高峰校验也不排队。任务想立即触发就立即触发,想定时跑一遍、按周期自动跑,界面上点点就配好了。存量加增量全覆盖——这就是"全周期"仨字的实际含义,不是宣传词儿,是两种机制各管一段,实打实。
四、校出差异之后:修复才是闭环
校验发现问题,才走完一半。怎么处理,决定这套东西好不好用。
KFS发现两端对不上,第一时间邮件、短信、微信、钉钉,哪个顺手推哪个。然后你面前摆两条路。
**手动修。**可视化界面选中差异表,定位到具体记录,做记录级修正。涉及账务的数据,估计你也不放心让程序自动动它——先人眼过一遍再改,稳。
**自动修。**打开全自动数据修复,比对出的差异KFS直接修掉,全程不用人盯。链路多、表多、7×24跑的系统就吃这套——白天人看着,晚上和节假日它自己收拾自己。
手工修大概是这个感觉(从源端捞一行,补到目标端),KFS把这动作自动化了:
-- 差异报告定位到某条记录后,修复的本质就是把这一行对齐
UPDATE finance.settle_detail t
SET (amount, upd_time) = (SELECT s.amount, s.upd_time
FROM src_link.finance.settle_detail s
WHERE s.id = t.id)
WHERE t.id = '20260904000123';
图形界面装不了的环境(安全要求苛刻的生产网段,懂的都懂),KFS还有命令行版的校验修复工具,功能一点不打折。
修复的底气来自链路自己的容错:断点续传,故障恢复后从断点接着来,不重传;数据库、网络、同步程序出问题,实例自动重启、自动重连;再往上还有多实例热备,主同步节点挂了备节点直接接管,实测切换10秒以内,全程不用人伸手。
北京市政交通一卡通的清结算系统,算是把这整套全用上了的综合案例:1.8亿用户、12.3TB存量,Oracle集群整体搬到KES读写分离集群,存量迁移3天内搞完,之后每天500GB增量保持秒级同步,一致性就靠不停机的实时自动比对加修复。清结算这业务,一分钱都错不得,这场景都能跑住,还有什么好挑的。
五、把校验塞进迁移流程:0停机切换的正确姿势
前面这些能力攒一块儿,才是KFS的平滑迁移方案。四步:
- KDMS迁移评估工具做结构迁移;
- KDTS迁移工具基于SCN/LSN快照搬全量;
- 全量一启动,KFS同时开始解析全量起点之后的增量日志,缓存在本地。这步是灵魂——全量跑三天还是三礼拜都无所谓,增量一直在那儿攒着,跑不丢;
- 全量完事儿,KFS把攒下的增量灌进目标库,直到两端SCN/LSN完全追平。这时候停应用,连接串一改指向新库,重启,收工。
业务真正停的时间,就最后切的那一小下。TB级存量,停机从"按天算"压到小时级甚至更短。
还想再稳一点?上双轨并行。新库上线不拆旧链路,反向同步拉起来,新旧两套库实时一致地并跑。新系统真出幺蛾子,随时切回去,进可攻退可守;等行业验证充分了,旧库再光荣退休。国产化替代走这条路,晚上能睡踏实。
写在最后
选异构同步工具,大家眼睛都盯着"支持多少种数据源""延迟几毫秒"。这些当然要看,但我劝你把另一个问题排到第一位:它怎么证明数据是一致的?
四个硬标准,自己对着量:校验是不是内置的,别回头再买工具写脚本;是不是在线的,不停业务、别把源端拖垮;存量增量是不是都罩得住;出了差异能不能自动修。四条全占,"数据无忧"这四个字才不算吹。
金仓KFS交的答卷——快照比对加KUFL增量校验、校验期间源端CPU负载增加3%以内、全自动的记录级修复——说实话,同类里我把话放这儿:能做到这么全的,少见。再加上301医院、人行征信、市政一卡通这些在产环境里真跑着的案例,选型的时候值得拉进来认认真真测一轮。
毕竟嘛,同步工具随时能换。丢出去的数据,可就真追不回来了。