数据一致性校验:对账系统的设计
珍珠与玫瑰
7 min read
判断先说:跨系统、跨库的数据只要经过网络和服务边界,就一定会发生不一致——消息丢失、重试重复、时序错乱、半成功。对账系统不试图杜绝这些,而是把它们变成"可定时发现、可定位、可修复"的常态事件。它是数据正确性的兜底防线,不是可选项,而是任何涉及资金或多系统协作的系统的必备组件。
为什么需要独立对账
主流程追求的是正常路径的性能和体验,补偿逻辑塞进主流程会让代码臃肿且不可靠。更关键的是,很多不一致发生在主流程之外:异步任务失败、下游消费超时、人工后台操作、跨日切账。这些场景主流程根本感知不到,只有用"第三种视角"周期性核对才能暴露。对账把"数据对不对"这件事从主链路里剥离出来,独立成一套可重复、可审计的机制。
两种基本对账模式
双向核对(全量对账):以某一时间为界,分别取出系统 A 和系统 B 的账户或订单快照,逐笔比对状态与金额,找出"只有一边有"或"两边金额不等"的差异。这是最严谨的方式,能发现任何单边遗漏。
以 T 日为例:
A 系统成功流水: {o1:100, o2:200, o3:300}
B 系统成功流水: {o1:100, o2:200} ← o3 缺失
差异: o3 在 A 成功但 B 缺失 → 标记待补单
单向核对(流水钩稽):只核对总额或勾稽关系,例如"每笔出账必有对应入账""当日应收合计等于已收合计"。适合数据量大、无法逐笔拉全的场景,先做粗筛再下钻。它的成本低,但只能发现问题存在,定位具体哪笔还要二次核对。
两种模式常常组合:先用单向核对圈定异常时段,再对异常时段做双向逐笔核对,兼顾效率和精度。
对账的核心难点
时间窗口对齐。两个系统的"完成"不是同一时刻。A 在 23:59:58 成功、B 在次日 00:00:03 落库,若按自然日切账,会被误判为差异。做法是用"业务时间"而非"处理时间"划窗,并给相邻日留重叠缓冲期,让跨日记录有第二次对账机会。忽视这一点,对账系统会产生大量"假差异"淹没真问题。
幂等与去重。对账任务本身也可能重复跑、崩溃重跑。每条差异记录要带唯一键(如 biz_date + biz_id + diff_type),重复比对只更新状态不重复插入,避免差异表自己膨胀成噪音。否则一次重跑就制造一批重复差异,反而让人无法判断真实情况。
状态机而非布尔判断。差异不是"永久错误",而是有生命周期:待核对 → 已确认差异 → 已修复 → 已关闭。中间可能经过自动修复(补单、冲正)和人工确认。用状态字段驱动,才能区分"真问题"和"正在处理中",也方便统计各阶段积压。
CREATE TABLE recon_diff (
id BIGINT PRIMARY KEY,
biz_date DATE,
biz_id VARCHAR(64),
diff_type VARCHAR(32), -- MISSING / AMOUNT_MISMATCH / STATE_MISMATCH
status VARCHAR(16), -- PENDING / FIXED / CLOSED
retry_cnt INT DEFAULT 0,
UNIQUE KEY uk_biz (biz_date, biz_id, diff_type)
);
自动修复与人工兜底
简单差异可自动处理:B 缺失且 A 确认成功,则触发 B 补单;金额不等则按权威方为准冲正。自动修复要写修复流水并溯源,方便事后审计。复杂或金额巨大的差异进入人工队列,由运营在核对上下文后处置——不能为了"自动化率"把高风险修复也自动做了,那等于把风险从数据层转移到自动脚本上。
监控与闭环
对账系统产出的是"差异率"和"未关闭差异数"两个核心指标。差异率突变(例如从万分之一跳到百分之一)往往是上游出了系统性故障的前兆,应设阈值告警。未关闭差异要有时效 SLA,防止差异堆积成"大家都默认忽略"的烂账,那样对账就失去了意义。
经验上,对账最容易被忽视的是"无差异时的验证":脚本空跑、数据源连错、字段映射错位时,也可能"恰好零差异"。要加入数据量基线校验(今日笔数是否与昨日同量级)和抽样人工复核,确保"零差异"是真的没差异,而不是对账逻辑自己失效了。一个静默失效的对账系统,比没有更危险,因为它给人虚假的安全感。
对账的时机与频率
对账不是越频繁越好,要在"发现问题及时"和"系统开销"之间平衡。资金类核心链路可以做到准实时或小时级,普通业务按天对账即可。关键是错峰执行:对账要拉取两个系统的数据做比对,本身也是一笔不小的读负载,放在业务低峰跑,避免和正常流量抢资源。对于历史已关闭的差异,定期归档而不是无限保留,否则差异表本身会变成大表,拖慢对账查询。一个健康对账系统的标志,是差异率长期稳定在一个极低且可解释的水平,而不是永远为零。永远为零反而要警惕是不是对账逻辑没真正跑起来。
差异修复的安全边界
自动修复看似省事,但每一步都要守边界。补单前必须确认"权威方确实成功",否则可能凭空造出一笔成功记录;冲正金额要以原始流水为准,不能凭当前余额推算,避免叠加其他已发生的变动后出错。所有自动修复动作都要落审计日志,记录触发原因、操作前后值、执行时间,方便事后追溯。涉及资金且金额超过阈值的差异,强制走人工复核,不交给脚本自动决断。对账的修复环节一旦出错,可能造成二次不一致,甚至比原始差异更难理清,所以保守一点比激进自动化更稳妥。
对账数据的存储与归档
差异记录和修复日志会随时间累积,本身需要管理。按业务日期分表或归档,保留足够长的追溯期,过期数据转入冷存储。对账跑批本身的执行日志也要保留,便于排查"某天差异突增是因为对账任务失败了"这类问题。把对账系统自身当作一个需要被监控和运维的系统,而非一次性脚本,才能长期可靠地守护数据正确性。一个会被遗忘、没人看告警的对账系统,等于没有对账。
1 view
0 likes
0 comments