作者:闲鱼技术——百夜
概述
作为互联网公司,我们每天都会或多或少的和钱打交道。稳定性,资损,安全是我们业务和系统的不可逾越的底限。任何一次资损事件,公司都要蒙受资金损失,甚至某个资损赔付的金额公司完全承受不起,瞬间倒闭破产。资损事件,除了造成资金损失之外,还可能会引发公关事件,造成用户对公司的信任危机,动摇公司的群众基础。因此现在每个团队,尤其是涉及到支付的业务团队,都会非常重视资损防控工作。资损防控工作,虽然是目前最复杂却没有大招去解决的问题,但是通过各个团队投入,实践,分析和总结,还是沉淀一些经验和方法论。本文介绍一下资损防控的总体方法论和在闲鱼交易体系下的实践。
资损定义
资损定义:资损,就是任何由于产品设计缺陷、产品实现异常、员工操作错误等,导致公司或者公司客户蒙受直接或间接的资金损失。基于此定义,我们需要关注以下关键点:
- 资损产生的原因:产品设计缺陷、产品实现异常、员工操作错误。
- 资损产生的后果:给公司或者公司客户造成直接或者间接的资损失。
广义上,只要是系统运行后的资金和业务预期的资金不一致,都算资损事件。在资损故障处理过程中,如果资金还在公司体系内,比较容易处理,最终不会造成实际资损。但是资金一旦出了公司体系内,到了用户手中,造成用户损失的,公司必须赔付,如果是用户获利的,公司比较难追回。因此对于涉及用户的资金流出,是资损防控的重点。
资损防控整体方法论
- 所有的资损事件,都是由人造成的,所以资金防控的中心,一定围绕人这个核心来开展的。
- 所有的业务,都是通过应用来实现,一笔业务操作完成,留下的是数据。因此资损防控相关的能力建设,一定是围绕应用和数据来进行的。
- 资损问题,特别因为技术原因造成的,本身就是也bug,相信大家都清楚,bug是不可能被完全消灭,总是会有bug会遗漏到线上造成问题,有的会造成业务失败导致用户体验问题,严重的会造成稳定性问题,有的可能会有漏洞被用户利用,而有的会造成资损。因此资损问题,是不可能被完全消灭的。虽然资损问题不能完全消灭,但是我们还是可以通过一些方法和手段,尽量在产品上线之前发现资损问题规避掉(规避能力),如果产品上线之后发生也要能够及时发现(发现能力),发现之后能够及时应急处理(应急能力),降低资损事件造成的损失和影响。
- 对于资损风险,我们需要投入专门的资源(组织保障)去做防控相关的事前,并且需要制定相应的规范和制度能去保障每个人都按照相应的规范和制度去执行,规避掉部分风险。同时我们还需要对风险情况进揭示和披露,针对性的投入资源部署风险防控能力。
上文介绍了资损定义和方法论,方法论中提到了资损防控需要的三项能力:规避能力、发现能力、应急能力,下文着重介绍闲鱼实时发现能力的建设过程。
发现能力建设总体思路
发现能力的建设,主要是围绕数据核对来建设,来发现业务信息和资金不一致的问题。对于发现能力,关键的指标是覆盖率和时效。覆盖率代表的是资损问题是否能发现的问题,如果一个资损问题没有相应发现能力覆盖,一旦发生,造成的损失就是不可预估的。时效代表的是问题资损问题发生后的发现时长,假设一个资损事件每小时造成资损10万,那么一个小时后发现相比一天后发现,资损金额可以少230万,如果是每小时100万,就是2300万。如果时效能做到实时,并具备实时的熔断能力,甚至可以做到0资损。
技术背景
闲鱼有非常多的交易模式:普通C2C、B2C、验货宝、进货宝、回收、寄卖等等;那么在这么多的交易模式下,如何抽丝剥茧出一套通用的、实时的、易接入的资损实时发现能力?
先简单介绍下阿里为资损防控做出的两个平台:
- MAC平台:数据核对平台,可以对比两段sql运行结果,有区别可以报警。缺点:不具备实时性;如果太频繁跑sql会给数据库带来额外的巨大压力。
- BCP平台:实时数据核对平台,可以订阅各个中间件的数据,后定制脚本进行数据实时比对,并具有报警能力。
既然BCP能做到实时比对和报警,那我们这块能力去借助BCP就好,我们需要做什么?规范数据来源,统一BCP配置,统一BCP脚本。只要能做到规范统一,那大家去做资损防控的时间、学习成本,可以大幅降低。
数据核对分析
证实模型
- 证:代表的是此次业务发生的业务凭证,例如交易单和支付单,业务凭证记录着业务的来源,参与方,以及资金相关信息
- 实:实,代表的是实际的资金流动。支付宝进账、出账,银行卡进账、出账
业务规则模型
- 我们的系统中,往往会很多各种各样的业务规则,这样业务规则的运转是否符合预期,也是需进行核对的。举个简单的例子,我们需要抽订单10%金额当作验货费,而验货费又要按照一定百分比分给平台和验货商,当这三个百分比任意一个配置错误,或代码出bug计算错误,都会导致平台和验货商产生资损问题。
简单总结:
有了这两个模型,套用一下,我们的数据核对链路就是证实核对链路,而证和实都是由业务规则产生的。那么其实可以从交易流程上去做规范:要求各业务必须要有"证"在订单信息上,即提前根据业务规则算出各方结算金额,并把信息放到订单上;当交易流转到需要结算的状态时,拿着我们设置好的预期结算金额(证expectedAmount),去结算平台查实际的结算金额(实actualAmount),当expectedAmount != actualAmount,那业务侧或结算侧必有问题。
架构设计
刚才我们也分析出来了,我们需要用expectedAmount和actualAmount进行比对,接下来就是从技术角度去实现,整个比对流程要规范化、易收口、可回溯。
从技术实现上来讲,我们需要把BCP层做轻,因为它只是个工具,核对需要写脚本,脚本本身就不容易验证也不好维护;我们只要有统一格式的对账数据,统一的对账接口,那么BCP的脚本就能做到完全一致,一个新的业务在BCP层只需要复制粘贴,改一下报警接收人,即可实现实时的资损防控。
下面是完整的架构图:
涉及到的系统介绍:
- 交易处理服务:交易相关的代码在这里,也会收中台履约流程发出的MQ消息;
- 交易中台:处理订单履约通用逻辑,订单履约就是创单、发货、交易完成等;中台完成每一个履约阶段,都会发出一条MQ消息通知业务方;
- BCP:多次提到了,实时数据核对和报警的平台;
- 结算平台:按照业务和规则,真正把钱分出去,一般是分给平台或服务商。
大家可以重点看下数据流向,我提两点:
- 统一格式的数据:收到中台履约消息后,我们可以根据配置好的对账规则,从订单信息中解析出来统一的数据,再发给BCP。最简的理解,我要拿到预期结算金额expectedAmount。
tips:
- 规则放在动态配置平台,如ducc上
- 数据解析可以引入规则表达式,如MVEL;有了规则表达式就会更加灵活,能覆盖更多的业务
- 统一的对账接口:既然已经有了统一格式的数据,那么我们的接口的格式也可以定义出来了,接口要做的就是去结算平台查到实际结算金额actualAmount,然后比对expectedAmount是否和actualAmount相等,不相等告诉BCP不等,让BCP去报警就可以了。
总结
本文主要描述了资损实时发现能力建设的过程,目前已赋能闲鱼验货宝,进货宝,C2B寄卖等9个业务;从技术角度来看,资损防控这件事其实和业务问题是一样的:要先把问题总结抽象出来,最后用技术去解决;并且一定要善于借助现有平台的能力,不要重复造轮子。方案的实现主要包括:
- 问题抽象,设计出一条完整的证实比对的链路;
- 使用MVEL表达式进行订单数据解析,来实现更高的覆盖率;
- 使用实时比对平台(BCP)进行数据比对和报警;
- 实时比对平台(BCP)写脚本使用泛化调用去调接口,避免引入任何业务包;
- 统一对账接口使用策略模式,根据对账类型进行策略定制。
有了发现能力是不够的,我们还需要完整的规避能力,和应急能力,这样资损防控才能成为体系,让业务安全的跑在资金链路上。