前言
在分布式系统中,虽然我们会使用各种分布式事务的方案,来保证各个系统之间的一致性。但是,很多时候往往事与愿违。
尤其是现在很多公司都采用最终一致性的方案,而所谓最终一致性,无论是本地消息表、事务消息、还是任务重试,系统之间的调用都是有可能失败的。
而一旦发生失败,就需要有一套机制来发现这些不一致的问题,这时候就需要做数据对账了。
对账时机
一般来说,根据对账的时机分为两种,离线对账和(准)实时对账。
实时对账,一般来说基本都是准实时,也就是说并不能保证无延迟,但是一般可以控制在秒级别的延迟上。而离线对账一般都是D+1的核对。
D+1:D指的是自然日,包括工作日和节假日。+1指的是第二天,也就是说数据发生后的第二天进行核对。
T+1:T指的是交易日,一般来说就是工作日,所以T+1指的就是数据发生后的下一个工作日进行核对。
技术实现
那么对账的技术实现上一般主要就是两种,要么是写代码核对,要么是写SQL核对.
写代码就是查出需要比对的两条记录,然后进行字段的比对,不一致的就抛出来。
写SQL就是做join查询或者子查询,然后通过where条件比较需要核对的字段,不一致的就抛出来。
写代码这种核对方式,一般来说都是通过定时任务实现的,通过运行定时任务,然后去扫表,或者去远程拉数据然后在业务代码中进行核对,这种方式的优点就是比较通用,不管是数据库,还是文件,还是远程接口,都可以做核对。缺点就是一旦数据量大了,代码核对的时效性就会比较差,而且代码运行存在失败的可能。万一数据量特别大,就可能会出现扫表扫不动,文件加载到内存导致OOM等问题。
所以,写代码的核对方式不推荐
那么,更好一点的方式就是写SQL了,因为数据都在数据库(数仓或者大数据框架)中,这些都可以通过SQL进行查询,如下就是比较两个系统中金额是否一致的SQL:
SELECT OUTbiz NO,bill NO,
OWNER
FROMbill item
WHEREOUT biz NO IN (AND charge ON amount - charge off amount = 0’ SELECTbiz id FROMcollectionCASEitem detail WHERECASEitem state = "COLLECTING" AND cur ovd principal >
那在哪写这些SQL进行核对,就有很多种方案了,一般来说有以下几个:
1、离线数仓,主要用于离线数据核对。我们现在每天会把需要离线存储的数据同步到数仓中,然后在数仓中写SQL进行数据的核对。
2、在线数据库,离线核对的话发现问题比较慢,好一点的方案是在在线库做核对,可以直接在数据库中写SQL进行数据核对。为了避免数据核对影响真实业务,可以考虑在备库中执行SQL。但是有的时候数据核对可能是多个系统之间的,这时候就要做跨库join,但是并不是所有的数据库、所有的引都文持跨库join的。
3、准实时数据库,还有一种方案,那就是不直接在数据库中写SQL,而是把数据同步到其他的地方,比如通过监听binlog的方式,把MYSQL的数据同步到实时数仓,比如我们公司内部用的就是AnalyticDB,把需要做核对的数据同步到ADB中,我们会尽量放到一个空间下面,然后在这里面写SQL作核对。同步出来的这个ADB数据,不仅可以做核对,还可以用于查询或者做报表,
4、ETL核对,还有一种比较常见的方案,那就是通过ETL工具进行数据核对,ETL包括了数据的提取、清洗、转化及加工,所以在这个过程中也是可以做核对的。
5、flink核对,flink是一个非常牛X的流处理框架,可以通过fink进行数据核对。
核对与告警
有朋友提问:如果通过sql语句发现有不一致的数据,一般是怎么处理?是发告警通知开发人员还是说需要将有问题的数据标记出来过段时间重新核对?
我们一般来说,告警的话,人工一定要跟进
至于说过段时间重新核对,这种我们一般在报警规则中把他屏蔽掉了。有需要重新核对的,我们会做一些延迟核对,或者二次核对。或者直接报警规则设置成多次失败后再报警,或者告警值调高一点
这样就是职责单一,核对就是核对,报警就是报警。有报警人就要看,否则都是无效报警,那有效报警也没人看了.