作者:孙庆昊
团队:资产管理
感谢开发小伙伴七宝、小鱼儿在项目中辛苦付出!
随着有赞的业务增长,单量与日俱增,业务场景变得越来越复杂,迭代的速度变得更快,出现故障的概率更大,从而产生的资损可能性也变大,这无论对于有赞本身还是对于有赞的商家来说都是很可怕的事情,我们要保证商家在有赞做生意是安全的、值得信赖的,所以及时发现问题、及时止血变得极其重要。同时,我们发现由于业务场景变得复杂,开发人员和测试人员也疲惫地奔波在各种场景的测试中,捉襟见肘,所以需要一个可以通过表中数据反推迭代的代码逻辑、和相关配置是否正确,在这种背景下,我们建立了核对体系,资损防控系统应运而生,我们也可以叫它实时核对系统,今天我们介绍核对体系中资损防控的第一部分:事前和事中处理。事后处理,例如:熔断止血、差错处理等,我们放在下一遍详述。
核对体系: 资损防控系统:也可叫实时核对系统 离线核对:内部核对、机构核对和实收核对等 差错系统:渠道差错、业务差错、实时核对差错等
基于前面说到的背景,资损防控平台在18年开始建起,在不断探索中,历经两版,我们暂且称第一版为基于sql方式核对,第二版为硬编码方式核对:
版本 | 优点 | 缺点 |
---|---|---|
基于sql方式 | 1入门简单,配置门槛较低2.sql脚本易于理解 | 1.主动拉取数据,占用sql查询资源2.sql方式核对,性能较低,例如:索引问题3.表中大字段问题没办法解决,例如:字段中存有json串4.业务方表结构DDL后,资损防控感知困难5.业务方对表数据DML后,资损防控无法感知,可能导致资损 |
基于硬编码方式 | 1.可以看一笔单号在整个链路上每一个环节的核对结果2.通过监听binlog消息解决了表数据DML后造成资损的可能3.解决表中大字段问题4.Hbase存储待核对数据,读写性能较高 | 1.硬编码编排核对链路,降低开发效率,不易维护2.与业务链接紧密,开发人员理解业务成本过高3.检测链路脆弱,一个环节修改导致整个链路存在问题4.规则不能掌握在业务方手里,相对于业务方来说变成黑盒 |
通过比较,我们知道第一版与第二版的区别,其中各有利弊,在不同时期解决不同的问题。我们基于两年的探索,充分了解了资损防控开发者、业务方或使用方的痛点,通过各种业务场景的抽象,得出核对模型,推出最新一版资损防控平台,就是这样,我们有了“今生”。
“今生”要解决什么问题?我们通过前期的积累,无论从系统性能和扩展性上,还是需求收集、理解和整理上,我们要解决几点问题:
在说今生之前,我们先聊聊几个使用场景:
场景一:C端用户支付或是退款,清结算系统需要将用户支付的金额与退款金额轧差(简单理解:支付金额-退款金额)结算给商家余额账户,这样就需要将清结算系统中结算数据与账务系统收支记录做比对,两边是否相等,可能会出现两种资损的场景,多结或是少结,也就是长款或是短款; 场景二:C端用户重复支付的情况,收单系统是要自动将多支付的金额退给用户的,这时就需要核对有赞是少退还是多退; 场景三:系统重构后,从老系统切流到新系统这个过渡期间,会有双写的情况,所以需要核对切流过程中两系统中是否数据正常,状态金额都需要核对; 场景四:当开发人员手动通过DML修改数据库表的数据,导致修改成错误的金额,影响接下来的一连串的错误,并造成资损,所以我们要核对修改后的数据与上游的数据或是下游数据是否存在差异。
在事前与事中处理这部分,我们一共分为5层:数据来源层、收据收集层、数据转化层、数据核对层和异常处理层
在技术架构图中,已初步简单聊过binlog从进入资损防控平台、核对、报警整个过程,就不过多赘述,这里有几点作为补充聊聊:
对于资损防控平台最重要的一点之一,就是尽量不能丢binlog数据,极小范围丢失是在容忍限度之内,当大范围丢失消息,会产生大量报警,是不能容忍的,而往往出现异常的可能就是,当多方binlog消息在同一时间进入同一个核对池子中时,为了避免Hbase中数据覆盖的情况,所以要顺序消费,并判断库表中数据产生的binlog消息的顺序号(sequenceNo),所以启用分布式Bond锁,将未获取到锁的数据消息重投,放入另一个消息队列,等待消费,重试策略会按两个维度,一个是重试次数,第二个是重试时间(时间按升序排列,每次重试的间隔时间会越来越长,直到达到最大重试次数),通俗的讲就是同一个房子,大家不能一起涌入,要排队,一个个进入,进入房子后,会按顺序分床,避免大家在无序状态下可能躺到一张床上;
这个检测点是资损防控定义的一个概念,其实很好理解,就是库表中数据每变化一次,产生的binlog就是一个检测点,例如:同一条数据当状态变更时,初始状态1,生成一个检测点,状态变更到2,再生成一个检测点,两个是不同的检测点,都会触发核对任务;检测点另一个作用是只存储了待检测数据在Hbase中的rowkey,而不存实际待检测数据;同时,检测点是以分库的形式存储在Mysql中,这就引出下面的一个内容:分片策略;
使用场景
时序图
为什么使用分片策略?
分片策略降级
当应用Redis做的顶层分片策略,由于网络或是其他原因导致不可用,平台会自动降级到随机分片策略,但是随机分片策略可能造成检测点捞起不均匀,在短时间内是可以做到不影响核对任务,当自动检测到顶层分片策略可用后,会自动升级到顶层分片策略。
为什么要使用动态监听器?
使用Redis与本地缓存(TMC)结合使用,对于核对规则的热点Key,从Redis中拉到本地缓存中,系统从本地获取规则信息,减小远程IO,提升binlog消息处理和核对任务效率,减小Nsq消息RT时间,提高消息处理吞吐量,规则版本控制器定时刷新Redis中核对规则,保证核对规则在缓存中为最新版本。
有三个重要作用:
核对体系依然在不断的持续完善中,无论是技术、业务和性能上,这其中充满很大挑战,我们在探索的路上持续进步前行,为有赞的业务保驾护航,做商家资金管理的坚强后盾,这篇文章只是提供个思路,不同公司有不同的业务场景和体量,做法一定会有所不同,希望对各位小伙伴有所帮助,成为资金安全上的铺路石。