架构师必备:实时对账与离线对账
背景
在跨系统之间的数据写入场景下,上下游系统极有可能因为网络超时/抖动、或写本地 DB 与调外部接口不能同时成功等原因,而出现数据不一致的问题,因此需要有及时发现不一致问题、并自动修复的能力。下面结合笔者的经验,把对账做个总结。
需要注意的是,这里提的对账不特指资金对账,而是跨系统的字段对账,如 B 端与 C 端系统之间的对账。
对账的指标
判断对账是否做得好,主要看这几个指标:
完备性:确保所有字段都有对账
时效性:越高越好,秒级 > 分钟级 > 小时级 > 天级
自动修复:对账发现不一致后自动修复,然后再次对账,确保修复后是最终一致的,形成闭环
下面分别介绍一下实时对账、离线对账,最好是两个都做。
1. 实时对账(秒级到分钟级对账)
实时对账可以尽快发现不一致,一般由数据写入方发起对账,数据接收方提供对账查询接口(例如查从库)。
触发方式分 2 种:
(不推荐)数据库变更事件触发:监听业务主表的 binlog 变更
(推荐)业务消息触发:监听业务消息变更
推荐由业务消息触发,是因为数据库变更事件触发有局限:
如果有的写入操作不更新业务主表,比如只更新了扩展表,则需要新消费扩展表的 binlog 事件消息。
如果存在中间状态,则需要等到记录变成终态后才能对账,需要过滤很多无效消息。
实现方案:
监听业务消息变更。业务消息需做成事务消息,即业务操作完成必发出、不完成不发出。业务消息可以携带多个表的信息,能减少一定的查 DB 请求。
延迟、批量消费变更消息,然后批量查询本地 DB 数据、以及上下游接口。
最后逐个字段做比较。

之所以要写入方发起对账,而不是接收方,是因为写入方调接收方的接口可能失败,接收方在写入失败时无法触发对账。
之所以要延迟消费,是为了避免短时间内的不一致造成误告警(例如数据库主从延迟、接口超时重试等原因),比如延迟 15 秒再消费。
之所以要积攒一批消息做批量消费,是为了避免对账查询 qps 过高,给本服务和上下游系统带来较大负载。
2. 离线对账(小时级到天级对账)
有了在线对账,为什么还需要离线对账呢?
离线对账作为在线对账的兜底,可以定期跑历史存量数据
离线对账不影响在线业务的稳定性
外部第三方系统,一般只能定期提供离线数据,无法提供对账查询接口。典型的如第三方支付系统的对账单
实现方案:
离线采集:导出各系统的数据到 hive 表,可以是 mysql 表、或者是对账单
归一化数据:解析出所有的对账字段,按统一格式生成新的宽表 a、宽表 b
离线对比:
(1)需要比较条数是否一致
(2)以及数据内容是否一致:通过左连接找到只存在于左表的数据,通过右连接找到只存在于右表的数据,通过内连接并比较各个字段来找到存在差异的数据
下面看 sql 例子。
3. 自动修复
一般是写入方发现不一致后,需要做自动修复。流程如下:
记录差异,供后续定位排查
自动修复
修复后再次对账,确保数据最终一致
结论
实时对账和离线对账,互为补充、缺一不可。新需求除了保证功能正确性,还要同时做好对账,避免有不一致问题时发现不了,或很久才发现。
对账发现不一致后自动修复,能保证系统的最终一致性。
文章转载自:Java烘焙师
评论