比对工具:渐进式改造跑得通的隐形基础设施

Mannnnning 2026-06-09 19:53 1

比对工具,我做老系统改造时唯一不省的东西


8 年里我反复总结过一句话:


老系统改造,新老两边的输出如果不能用工具自动 diff,就只能
靠人盯。靠人盯一定会漏。


漏的不是大 bug——大 bug 上线 1 小时就报警了。
漏的是那种"看起来对但不对"的——单跑任何一边都看不出来,
机器把全量数据 diff 一遍,问题才浮出来。


下面是 4 个例子,都是真实经历过的项目,做了脱敏。




例 1 · 订单类系统迁移的 dump 比对


上篇提过的"老语言迁到主流语言"的项目,跨 14 个月切完。


这 14 个月里整个迁移就靠一件事撑着:dump 比对


老系统的事件流 dump 一份,新系统的事件流 dump 一份,
每天定时跑 diff,差异写报表。


期间发现的 11 个"看起来对但不对"的 bug——全部是 diff
报表先发现,人后看到的


最典型的一类:同一个业务状态,老系统用字符串表达,新系统用
枚举表达,两边语义其实一样。下游消费方两套都能解析——直到
diff 报表跑出来"同一条记录两种表达",我们才意识到出了问题。


如果当时省了这套——切完后只会有一堆历史数据不一致,
**到时只能选:全量重跑(代价大),或者认账(留坑)**。




例 2 · 聚合查询系统的跨结果表对账


某个聚合查询系统有 2 张结果表,逻辑上 1:1 对应。


跑了 5 年,某天我们顺手算了一下——
有上千条核心业务记录在表 A 有,表 B 没有


是某个增量更新的边界 bug 。
不大,数据缺失也不影响主业务流程,所以 5 年没人发现。


后来加了个简单工具——


每天 1 次,表 A vs 表 B 跑 diff,差异 > 阈值告警,告警里
带具体写入代码段的指针。


工具上线 1 周,问题暴露;3 周修完。


值得说的是:**前 5 年是"暴露不出来",不是"修不了"**。
代码本身一直在那,bug 不是隐蔽,是没人有手段看见它。




例 3 · 数据匹配的离线 vs 在线 diff


某个数据匹配场景有两条链路:



  • 离线全量(每天凌晨重算所有匹配关系)

  • 在线增量(数据有变更时,即时算)


逻辑上两条应该一致——但实际经常不一致。


我们的比对方式很简单:取 1% 数据,让两条链路同时跑同一份输入,
diff 输出。每周大概能跑出 50-100 条不一致。


有意思的是:这些不一致里只有 30-50% 是真 bug
剩下的是真实业务边界——比如某些场景在线已经能感知到、离线
还没扫到——这种"差异"是合理的,标"忽略"。


你必须能看到它,才有资格忽略它
没有这套工具的时候,我们以为两条链路一致;有了之后才发现:从来
就没一致过,只是没人在比。




例 4 · 多源数据合并时的字段分布对比


某个数据合并场景中,不同来源的数据语义不完全一致。
字段分布(枚举值频次 / 数值范围)是一种隐含约束


工具:合并前后跑同一个字段的分布,漂移 > 5% 就告警。


发现过一个特别隐蔽的 case——


枚举值"未知"在 A 来源约定是 0,B 来源约定是 -1 。
单看代码看不出来,0 和 -1 都是合法值,谁也没写错。
但合并后字段分布告警立刻响:**"0"占比从 30% 降到 15%**——
回头查,才看出两个来源的"未知"约定不一样。


字段分布对比有时比代码 review 更准——
代码 review 看的是逻辑,字段分布看的是约定




不是 1 个工具,是 4 件配合用的事


很多人理解"比对工具"是写个脚本跑 diff——
这是把比对工具理解小了


我经历的几次大改造,每一次都是这 4 件事一起做:


                  ┌─────────────────────────────────────────┐
│ 老系统流量 新系统流量 │
│ │ │ │
└───────────┼──────────────────┼───────────┘
│ │
▼ ▼
┌──────────────────┐ ┌──────────────────┐
│ ① 数据快照 dump │ │ ① 数据快照 dump │
│ (独立存储) │ │ (独立存储) │
│ 解耦 / 毫秒级 / │ │ 字段冗余比节省强 │
│ 字段冗余 │ │ │
└─────────┬────────┘ └─────────┬────────┘
│ │
└─────────┬──────────┘

┌──────────────────┐
│ ② diff 报表 │
├──────────────────┤
│ ▸ 字段级:A.x≠B.x │
│ ▸ 结构级:有/无 │
│ ▸ 时间级:早/晚 N 秒│
└─────────┬────────┘

┌──────────────────┐
│ ③ 告警分级 │
├──────────────────┤
│ P1 关键字段差异 │ ──→ 立即告警
│ P2 非关键 > 阈值 │ ──→ 邮件
│ P3 时间级 < 容忍 │ ──→ 入归档
└─────────┬────────┘

┌──────────────────┐
│ ④ 回溯链路 │
├──────────────────┤
│ 报表保留 ≥ 30 天 │
│ 改动有版本号 / 时间戳│
│ 时间窗口反查 │
└─────────┬────────┘

根因定位
"哪次改动引入的"

① 数据快照 dump


老新两边都要把关键事件 dump 到独立存储。


3 个细节:



  • 跟主链路解耦(dump 故障不能影响业务)

  • 时间戳精确到毫秒

  • 字段冗余比节省强(多 dump 一些没坏处,少 dump 一个就废了)


② diff 报表


定时全量或采样跑 diff,差异分类:



  • 字段级差异(A.x ≠ B.x)

  • 结构级差异(A 有 B 没有)

  • 时间级差异(A 早 B 晚 N 秒)


不分类的 diff 报表等于没看——一堆条目堆在那,人会习惯性忽略。


③ 告警分级


不是所有 diff 都告警。



  • 业务关键字段差异 → P1 立即告警

  • 非关键字段差异 > 阈值 → P2 邮件

  • 时间级差异 < 容忍窗口 → 入归档,不告警


不分级 = 全告警 = 等于没告警——3 天后没人看了。


④ 回溯链路


发现 diff 后,要能定位具体哪个改动引入的


要求:



  • diff 报表至少保留 30 天

  • 所有改动有版本号 / 时间戳

  • 按时间窗口能反查


没有回溯能力的 diff,等于"看到 bug 但不知道怎么发生的"。


这 4 件事缺一件,比对工具就只是"看起来在比"。




什么时候不该做


也有反例。


某次小项目,1 个 service 重构,代码量不到 500 行。
我也想搞这套——leader 直接砍了:"投入 vs 产出比不合理。"


事后看是对的——那个 service 切完后没出过故障。


我大概的判断:



  • 千行以内 / 周级别的小改造——别上,没必要

  • 上万行 / 月级别以上的大改造——必上

  • 中间档——看两件事:数据语义复杂吗?并跑会持续 1 个月以上吗?
    任何一个"是",就上




写在最后


很多人会把"比对工具"归在测试的事——
我倾向认为是改造方案的一部分。


测试问"这次发布有没有 bug"。
比对工具问"接下来这 N 个月,新老两边到底一不一致"。
看的时间尺度不一样。


而且时机很重要——
比对工具要在切第一刀之前就上线
切完一半再加,你已经分不清"这条差异是改造带来的,还是早就存
在的"。




写到这,我也不太确定这套对所有团队都成立。


我经历的项目都是"业务相对稳定 + 改造期长 + 数据要追溯",
这种场景比对工具几乎是必修。
但如果是高速迭代的创业团队,搞这套可能反而是负担——


这点我自己也还在想。


下一篇打算写 6 阶段验收 SOP——
比对工具是其中第 4 阶段的核心,正好顺着接。


(以上 4 个例子都做了脱敏。
如果你做过老系统改造,欢迎评论区聊聊你们的比对工具长什么样,
特别想听没搭比对工具直接切,后来踩过的坑。)



最新回复 (0)
    没有回复
* 帖子来源V2EX
返回