支付场景一致性原则规范
1简介
1.1范围
本文从客观实战出发全面梳理支付一致性相关场景 ,针对不同的场景给出最佳实践,并归纳出通用的一致性设计原则。
本文描述的是支付不同场景下需要保障最终一致性的对象的规则实践,针对一致性保障手段不做细节展开,例如分布式事务技术。
2一致性设计原则
本章节针对一致性设计共性原则进行归纳总结。其中分为三个档:**“严禁”原则是红线原则必须遵守不允许任何例外情况;“必须”原则是相对刚性原则,原则上必须遵守,特殊情况允许例外且特殊情况必须评审备案;“尽可能”**原则是相对柔性原则,引导设计方向正确性,建议尽可能遵守,允许例外但需要明确合理的理由,不强制评审但需要备案。
2.1严禁可能导致短款的强制终态原则
严禁在可能产生短款风险的相关处理中“强制终态”。以收单场景为例,在扣款结果未知导致超时的情况下,不能强制终态“扣款成功”。容易犯的错误:认为这种情况下如果强制为“失败”只会导致长款,不会产生短款。第一,产生长款会造成VOC风险;第二,如果强制终态逻辑存在使得产生错误设置终态成为了可能,一旦有逻辑错误误判或者终态设置逻辑其他错误,会提升导致短款的风险概率;第三,强制设置终态的必要性不足,有其他的方案选择处理交易超时场景,没有必要采用强制终态这种风险概率较高的处理手段。
2.2严禁架构元素自行采用数据库DML方式自行修复资金安全相关问题原则
严禁在可能产生资金安全问题的相关处理中,通过数据库DML方式自行修复,需要纳入资金安全解决方案统一闭环处理。容易犯的错误:架构元素在发现出现“单面账”(一方有,一方无),自行通过数据DML直接修复消除。通常产生此类问题的原因相对复杂,不是通过简单数据层面修复就可以真正做到正确,而是纳入资金安全专业领域通过一整套包括异常识别、异常处理、交易稽核、差错处理等完善的解决方案去闭环处理。注:系统BUG造成的必须由数据层面修正的情况,必须经过评审走审批流程执行落地,建议能够纳入资金安全处理的尽量纳入。
2.3必须架构元素一致性自闭环不信任原则
要求各个架构元素确保一致性保障能力自闭环。本原则最核心的要求是不能依赖其他架构元素(通常是上下游)来保障自身架构元素的最终一致性。以退款场景为例,退款本身是需要校验原单是否存在且可退金额是否足够等判断,通过之后才允许退款,支付交易链路较长,包括但不限于交易服务、支付核心服务、支付通道服务等关键架构元素协同完成。容易犯的错误:下游架构元素(以支付核心服务为例)认为上游架构元素(以交易服务为例)已经做了原单校验和可退金额校验,只要做好幂等防止重复退款即可,没有做到“一致性自闭环不信任”,即不能相信上游架构元素的判断一定不会有问题(假设BUG无所不在),要自行完成自闭环的原单校验和可退金额校验再加上幂等等关键逻辑保护,才能做到足够安全。注意:这里任何瑕疵或者错误都是有可能导致“资损”的,必须基于审慎的大原则做到自闭环一致性判断。
2.4必须逆向原单校验原则
本原则规定在逆向交易中必须做到针对原单是否存在、关键信息是否符合业务规则进行校验(例如可退金额是否足够)。容易犯的错误:认为上游架构元素已经做了原单校验就满足要求了,本原则需结合“架构元素一致性自闭环不信任原则”,不能盲目把关键保障逻辑依赖其他架构元素的实现正确性,属于不安全实现。
2.5必须幂等避免资金或者资源重复处理原则
本原则规定凡是涉及资金处理相关操作必须做到“幂等”保护,且尽可能结合“幂等保护靠前”原则。**容易犯的错误:**对于业务正常处理已经终态的幂等保护容易设计实现,容易遗漏或者出错的是针对无法终态场景以及技术异常(例如数据库主键冲突)场景如何做到正确幂等。
2.6必须不自动换单重试原则
本原则规定不通过自动换单重试手段绕过幂等保护,导致幂等保护失效从而造成“资损”。差错修复场景经过完整审核审批流程下的“手动”重试可以例外。
2.7必须接口业务状态判断原则
本原则规定业务处理接口中的业务执行结果判断必须依赖独立的“业务状态”判断,不能与其他含义字段复用,亦不能通过多个字段组合判断业务执行结果。业务执行结果的判断正确与否是非常重要的,一旦判断错误后果严重,甚至会导致短款资损。尤其是多字段组合判断的情况下,即便没有逻辑错误或者BUG,但是随着系统的迭代演进,很可能造成已有的组合判断无法覆盖导致错误的结果。重要的事情说三遍,业务执行结果判断的依据必须通过“简单、单一、直接”的唯一字段进行判断。
2.8必须终态不可变原则
本原则规定业务处理中一旦生成“业务终态”则必须做到不能再改变,即在对业务状态进行写操作的时候要判断其是否已经终态,如果是则进入例外或者异常处理,绝对不能简单覆盖。
2.9必须出金预扣原则
本原则规定出金场景中必须对出金资金进行预扣处理,避免并发场景下重复出金的短款资损。之所以不强制要求加锁处理,是考虑提高并发能力。
2.10必须旁路处理不能破坏一致性核心对象间一致性原则
本原则规定在数据自动清理、状态异常自动或者手工修复、差错人工处理、资金安全异常识别与处理等旁路处理过程中,必须做到不能破坏所处理的一致性核心对象间的一致性。关键是业务场景的一致性核心对象以及如何规定各对象如何确保一致的规则,这个规则不能因为非交易本身逻辑而造成不一致,即各种异常修复、差错处理等辅助旁路操作要围绕同样的一致性对象和规则,如果有例外情况,遵循“必须”原则上升TMG评审处理。
2.11尽可能幂等资金处理保护靠前实现原则
本原则规定在实现幂等逻辑中尽可能把幂等相关处理逻辑放在前面,尤其是业务核心处理逻辑之前,避免核心逻辑幂等保护失效。
2.12尽可能不做强制终态原则
本原则规定在交易处理过程中尽可能不做强制终态处理,而是尽可能通过“处理中”、“受理成功”、“超时”等过度状态遵循客观事实本质反映实际状态,特殊例外情况遵循“尽可能”原则议事规则审议。
2.13尽可能不强依赖消息队列一致性实现最终一致性原则
本原则的“尽可能”是针对使用范围不是全部消息队列相关场景,而是针对通过消息队列异步递送的信息是最终一致性强依赖的情况下必须遵循本原则。本原则要求在实现业务最终一致性的时候,不要假设消息队列是可靠的、确保一致的,要对由于消息队列造成的不一致性进行容错。要假设消息队列无法确保一定按照约定确保消息处理的一致性,即放入消息队列的消息一定会被消费者消费掉。例如,用户签约、解约累计数量是通过消息队列异步通知实现的,如果不是基于这个假设对消息队列可能存在的“偶发”不一致,一旦发生就会造成最终一致性出现问题,则用户出现无法解约等产生VOC的风险,这种情况下必须在设计层面解决最终一致性保障问题。
3典型支付场景一致性核心对象一览
下表描述的是支付典型支付场景下需要保持最终一致性的核心对象:
场景名称 | 一致性核心对象(分号间隔) |
---|---|
银行卡支付 | 交易单;支付单;两联外部资金 |
银行卡支付原路退款 | 同上。 |
银行卡支付退款到余额 | 交易单;支付单;支付账户余额 |
余额支付 | 交易单;支付单;支付账户余额 |
余额支付原路退款 | 同上。 |
纯券支付 | 交易单;支付单;资金(营销账户圈存单);资产(券资源) |
纯券支付原路退款 | 同上。 |
纯营销支付 | 交易单;支付单;资金(营销账户圈存单);资产(营销资源) |
纯营销支付原路退款 | 同上。 |
C2C红包 | 红包单(红包主单+红包子单);交易单(对应红包主单);支付单(对应红包子单一对一生成红包圈存单);资金(与红包主单一致且与两联外部资金或者支付账户余额一致) |
C2C红包原路退款 | 同上。 |
C2C红包退款到余额(卡支付) | 红包单(红包主单+红包子单);交易单(对应红包主单);支付单(对应红包子单一对一生成红包圈存单);资金(与红包主单一致且与支付账户余额一致) |
B2C红包 | B2C单(B2C服务中的商户订单);支付单;出资金(营销账户圈存单);入资金(个人支付账户余额) |
线下转账 | 交易单(生成从商户视角相当于转入账号的“转账识别码”返回给商户,分为随机和固定两种,如需写入合同则只能采用固定);支付单;资金(扫描备付金入金流水根据不同类型识别码匹配规则识别出对应的转入流水,流水中的资金金额作为转入资金) |
线下转账原卡退款 | 对于客户视角是“原路退款”,所以一致性对象要求同上。 |
组合支付 | 交易单(1);支付主单(1N);支付子单(NM);资金(两联外部资金或者支付账户余额+营销账户圈存单);资产(券资源或者营销资源) |
组合支付原路退款 | 同上。 |
组织支付退款到余额 | 交易单(1);支付主单(1N);支付子单(NM);资金(支付账户余额+营销账户圈存单);资产(券资源或者营销资源) |
批量支付 | 相当于多笔银行卡支付批量独立执行,相互不存在一致性保障关系,具体详见“银行卡支付”一致性对象。 |
批量支付退款 | 同“银行卡支付”退款要求。 |
分账 | 分账单+分账子单(包括协议分账;实时分账;延时分账;POD分账均产生独立的分账单);组合支付单(支付主单+支付子单,对应分账单+分账子单);出资金(当前实现:商户待清算账户可用余额;未来演进:商户待清算账户圈存单);入资金(商户待清算账户可用余额) |
分账回收 | 分账回收单+分账回收子单(当前实际应用的场景只有一个分账回收子单,未来演进多余一个分账子单时需要再次审视设计完备性);分账回收支付单+分账回收支付子单(同上);出资金(商户待清算账户可用余额或者商户支付账户可用余额);入资金(商户待清算账户可用余额) |
分账回收退回 | 分账回收退回单;分账回收退回支付单;出资金(商户待清算账户可用余额);入资金(商户待清算账户可用余额或者商户支付账户可用余额) |
代付 | 交易单;支付单;出资金(商户支付账户余额);入资金(两联外部资金) |
充值 | 交易单;支付单;出资金(两联外部资金);入资金(账户余额:用户支付账户、商户支付账户、商户营销账户) |
提现 | 交易单;支付单;出资金(账户余额:用户支付账户、商户支付账户、商户营销账户);入资金(两联外部资金) |
商户清算 | 收单、退款、分账、分账回收、分账回收退回交易单;清算单:一批交易单汇总轧差计算得出清算单的已清算待结算金额,具体包括:1)清算金额(付给商户),2)手续费金额(向商户收取);清算相关资金:1)清算资金:待清算账户结转到已清算账户,2)手续费:待清算账户结转到手续费中间户(注:如果手续费为负值,则资金流从手续费户结转回待清算账户) |
商户结算 | 清算单;冻结交易单:风控等渠道冻结;结算单:清算单与冻结交易单的汇总轧差;结算相关资金:1)结算:已清算账户结转到商户支付账户或者两联外部资金(注:扫款为结算特殊分支,资金流分两步,第一步是从已清算账户结转到商户支付账户,第二步从商户支付账户扫款到两联外部资金。),2)手续费:手续费中间户结转到手续费账户 |
4典型实例:券组合支付场景
券组合支付场景为用户在支付过程中组合使用银行卡支付(或者余额支付)+券支付的场景。该场景涉及一致性核心对象包括:交易单;支付主单;支付子单;资金(两联外部资金或者支付账户余额);资金(营销账户圈存单);资金(营销账户可用余额);资产(券资源)。
其中,交易单落在交易服务,支付主单和支付子单落在支付核心服务,两联外部资金处理落在支付通道服务,支付账户余额处理落、营销账户圈存单资金处理、营销账户可用余额处理落在支付账户服务处理,券资源落在券中心服务处理。小结:券组合支付场景下需要至少上述五个服务系统保障一致性核心对象的“最终一致性”。
券资源(即券批次)的生命周期管理在券中心,券圈存单的生命周期管理在支付核心,二者必须完全对齐生命周期一致性,包括创建、核销、退款退券、差错闭环、运营资金统计。
4.1券圈存单与券资源的创建和绑定
券圈存单与券资源创建过程,实现二者一对一绑定,为后续一致性校验等打下基础,具体步骤如下:
1、 券圈存单的创建(生命周期开始)要早于券批次的创建;
2、 券批次的创建要绑定已经创建好的券圈存单,绑定成功后需要通知支付核心,支付核心也要同步把券圈存单与券批次绑定;
3、 券发放是用户和具体券资源绑定的过程。
4.2券核销中的券资源与券圈存单的一致性(一致性保障重点环节)
用户通过端侧(也可以是商户侧API)发起券组合支付,支付扣款(以银行卡扣款为例)后会触发“券核销”,具体步骤如下:
1、 交易服务接到该请求第一步必须遵循“必须幂等避免资金或者资源重复处理原则”以及“尽可能幂等资金处理保护靠前实现原则”完成幂等处理;
2、 交易服务第二步是向支付核心发起券组合支付指令,首先必须遵循“必须接口业务状态判断原则”来判断支付核心的券组合支付指令返回状态;券组合支付指令如果没有终态返回则首先必须遵循“必须不自动换单重试原则”不能自动换单重试,且尽可能遵循“尽可能不做强制终态原则”不做强制终态处理,尤其是必须遵循“严禁可能导致短款的强制终态原则”不能在返回状态未知情况下强制“成功”终态,避免短款资损;
3、 交易服务第三步是遵循“必须终态不可变原则”正确更新券组合支付指令的执行结果,并必须遵循“必须接口业务状态判断原则”通过独立业务状态返回券组合支付指令结果给到发起方端侧或者商户侧;
4、 支付核心接到券组合支付指令后,第一步必须遵循“必须幂等避免资金或者资源重复处理原则”以及“尽可能幂等资金处理保护靠前实现原则”完成幂等处理;
5、 支付核心第二步是向支付通道发起银行卡扣款指令,首先必须遵循“必须接口业务状态判断原则”来判断支付通道的银行卡扣款指令返回状态;银行卡扣款指令如果没有终态返回则首先必须遵循“必须不自动换单重试原则”不能自动换单重试,且尽可能遵循“尽可能不做强制终态原则”不做强制终态处理,尤其是必须遵循“严禁可能导致短款的强制终态原则”不能在返回状态未知情况下强制“成功”终态,避免短款资损;
6、 支付通道接到支付核心银行卡扣款指令,第一步是必须遵循“必须幂等避免资金或者资源重复处理原则”以及“尽可能幂等资金处理保护靠前实现原则”完成幂等处理;
7、 支付通道第二步是向两联外部通道发起银行卡扣款指令,首先必须遵循“必须接口业务状态判断原则”来判断两联外部通道的银行卡扣款指令返回状态;银行卡扣款指令如果没有终态返回则首先必须遵循“必须不自动换单重试原则”不能自动换单重试,且尽可能遵循“尽可能不做强制终态原则”不做强制终态处理,尤其是必须遵循“严禁可能导致短款的强制终态原则”不能在返回状态未知情况下强制“成功”终态,避免短款资损;
8、 支付通道第三步是遵循“必须终态不可变原则”正确更新银行卡扣款支付指令的执行结果,并必须遵循“必须接口业务状态判断原则”通过独立业务状态返回银行卡扣款结果给到支付核心;
9、 支付核心第三步是必须遵循“必须接口业务状态判断原则”通过独立业务状态以银行卡扣款结果为券组合支付结果给到交易服务;(注:券资源核销异步完成)
10、支付核心第四步是必须遵循“必须出金预扣原则”预先扣减与券资源绑定的券圈存单中的资金;
11、支付核心第五步必须遵循“必须架构元素一致性自闭环不信任原则”独立闭环校验核销出金过程中券批次与券圈存单绑定关系的正确性;
12、支付核心校验通过后,第六步是异步发起券核销指令到券中心,首先必须遵循“必须接口业务状态判断原则”来判断券中心的券核销指令返回状态;券核销指令如果没有终态返回则首先必须遵循“必须不自动换单重试原则”不能自动换单重试,且尽可能遵循“尽可能不做强制终态原则”不做强制终态处理,尤其是必须遵循“严禁可能导致短款的强制终态原则”不能在返回状态未知情况下强制“成功”终态,避免短款资损;
13、支付核心第七步是接到券中心核销结果终态后必须遵循“必须终态不可变原则”检查当前券核销状态是不是已经终态,如果是则需要抛出异常闭环处理;
14、券中心接到支付核心的券资源核销指令,第一步是遵循“必须幂等避免资金或者资源重复处理原则”以及“尽可能幂等资金处理保护靠前实现原则”完成幂等处理;
15、券中心第二步是遵循“必须架构元素一致性自闭环不信任原则”独立闭环校验券批次与券圈存单绑定关系的正确性;
16、券中心校验通过后,第三步是完成券资源的核销并必须遵循“必须接口业务状态判断原则”通过独立业务状态返回核销结果给到支付核心。
4.3支付核心自动解圈存机制兼顾券支付一致性要求
支付核心本身设计了自动解圈存机制,避免圈存单长期滞留在系统中一直不结束其生命周期带来的数据残留问题。在这个过程中必须遵循“必须旁路处理不能破坏一致性核心对象间一致性原则”,自动解圈存的规则要兼顾券圈存单与券批次是一致性强关联的情况。
4.4券中心的券批次到期处理要兼顾券支付一致性要求
券中心负责券资源(券批次)全生命周期管理,其中券批次过期过程需要联动支付核心券圈存单保证券资源与券资金的一致性,具体过程如下:
1、 券中心根据券批次有效期判断,到期触发券批次失效,必须遵循“必须接口业务状态判断原则”通过独立业务状态异步通知支付核心“券批次到期”;
2、 支付核心接到异步通知执行券圈存单释放回营销账户可用余额,必须遵循“必须架构元素一致性自闭环不信任原则”独立闭环校验券批次与券圈存单绑定关系的正确性。
4.5退款退券中的券资源与券圈存单的一致性(一致性保障重点环节)
商户侧发起退款退券,其中退款以退到银行卡为例,具体步骤如下:
1、 交易服务接到退款退券请求,第一步必须遵循“必须幂等避免资金或者资源重复处理原则”以及“尽可能幂等资金处理保护靠前实现原则”完成幂等处理;
2、 交易服务第二步必须遵循“必须架构元素一致性自闭环不信任原则”以及“必须逆向原单校验原则”独立完成原单校验,即独立判断该笔逆向交易针对的正向交易是否存在且符合退款退款规则判断,例如“可退款金额”是否足够;
3、 交易服务第三步向支付核心发起退款退款指令,首先必须遵循“必须接口业务状态判断原则”来判断支付核心的退款退款指令返回状态;退款退券指令如果没有终态返回则首先必须遵循“必须不自动换单重试原则”不能自动换单重试,且尽可能遵循“尽可能不做强制终态原则”不做强制终态处理,尤其是必须遵循“严禁可能导致短款的强制终态原则”不能在返回状态未知情况下强制“失败”终态,避免短款资损;
4、 交易服务第三步是遵循“必须终态不可变原则”正确更新退款退券指令的执行结果,并必须遵循“必须接口业务状态判断原则”通过独立业务状态返回结果给到发起方商户侧;
5、 支付核心接到退款退券指令,第一步必须遵循“必须幂等避免资金或者资源重复处理原则”以及“尽可能幂等资金处理保护靠前实现原则”完成幂等处理;
6、 支付核心第二步是必须遵循“必须架构元素一致性自闭环不信任原则”以及“必须逆向原单校验原则”独立完成原单校验,即独立判断该笔逆向交易针对的正向交易是否存在且符合退款退款规则判断,例如“可退款金额”是否足够;
7、 支付核心第三步是向支付通道发起银行卡退款指令,首先必须遵循“必须接口业务状态判断原则”来判断支付通道的银行卡退款指令返回状态;银行卡退款指令如果没有终态返回则首先必须遵循“必须不自动换单重试原则”不能自动换单重试,且尽可能遵循“尽可能不做强制终态原则”不做强制终态处理,尤其是必须遵循“严禁可能导致短款的强制终态原则”不能在返回状态未知情况下强制“失败”终态,避免短款资损;
8、 支付通道接到支付核心银行卡退款指令,第一步是必须遵循“必须幂等避免资金或者资源重复处理原则”以及“尽可能幂等资金处理保护靠前实现原则”完成幂等处理;
9、 支付通道第二步是必须遵循“必须架构元素一致性自闭环不信任原则”以及“必须逆向原单校验原则”独立完成原单校验,即独立判断该笔逆向交易针对的正向交易是否存在且符合退款退款规则判断,例如“可退款金额”是否足够;
10、支付通道第三步是向两联外部通道发起银行卡退款指令,首先必须遵循“必须接口业务状态判断原则”来判断两联外部通道的银行卡退款指令返回状态;银行卡退款指令如果没有终态返回则首先必须遵循“必须不自动换单重试原则”不能自动换单重试,且尽可能遵循“尽可能不做强制终态原则”不做强制终态处理,尤其是必须遵循“严禁可能导致短款的强制终态原则”不能在返回状态未知情况下强制“失败”终态,避免短款资损;
11、支付通道第四步是遵循“必须终态不可变原则”正确更新银行卡退款支付指令的执行结果,并必须遵循“必须接口业务状态判断原则”通过独立业务状态返回银行卡退款结果给到支付核心;
17、支付核心第四步是必须遵循“必须接口业务状态判断原则”通过独立业务状态以银行卡结果为券组合支付结果给到交易服务;(注:退券异步完成)
18、支付核心第五步必须遵循“必须架构元素一致性自闭环不信任原则”独立闭环校验退券相关券批次与券圈存单绑定关系的正确性;
19、支付核心校验通过后,第六步是异步发起退券指令到券中心,首先必须遵循“必须接口业务状态判断原则”来判断券中心的券核销指令返回状态;退券指令如果没有终态返回则首先必须遵循“必须不自动换单重试原则”不能自动换单重试,且尽可能遵循“尽可能不做强制终态原则”不做强制终态处理,尤其是必须遵循“严禁可能导致短款的强制终态原则”不能在返回状态未知情况下强制“失败”终态,避免短款资损;
20、支付核心第七步是接到券中心退券结果终态后必须遵循“必须终态不可变原则”检查当前退券状态是不是已经终态,如果是则需要抛出异常闭环处理;
21、券中心接到支付核心的券资源核销指令,第一步是遵循“必须幂等避免资金或者资源重复处理原则”以及“尽可能幂等资金处理保护靠前实现原则”完成幂等处理;
22、券中心第二步是遵循“必须架构元素一致性自闭环不信任原则”独立闭环校验券批次与券圈存单绑定关系的正确性;
23、券中心校验通过后,第三步是完成退券并必须遵循“必须接口业务状态判断原则”通过独立业务状态返回核销结果给到支付核心。
4.6资金安全兜底闭环资金流一致性
上述所有过程都是联机实时完成,属于交易事务或者准事务处理范围,即原则上要么全成功要么全失败的实时联机事务一致性保障范围之内。但是,无论多么完善的事务一致性保障措施,都因为BUG的无法完全避免,必须从另一个视角进行最终一致性兜底校验和修复,目前此类能力归入资金安全领域。
资金安全域的核心职责是独立从数据视图切入,直达数据底层进行一致性问题的识别,通过与各个支付业务域配合完成问题修复,包括异常识别、异常处理、业务稽核、差错处理等关键处理,来兜底闭环最终一致性。
资金安全域的处理是经过专业设计具备合理性、可靠性等必须满足能力规格的,且其能力是经过一系列质量保障措施检验的,是具备可信基础的专业能力域。所以对于其他领域,一致性兜底闭环方面必须遵守“严禁架构元素自行采用数据库DML方式自行修复资金安全相关问题原则”不能自行处理。
对于券组合支付场景,需要资金安全域闭环处理关于交易单、支付单、资金(营销账户圈存单)、资产(券资源)、两联外部资金的最终一致性。
一、核对场景
1、券批次与券圈存单一致性核对:需要实现券中心、支付核心双方券批次绑定的圈存单号是否一致的检查;
2、退款退券一致性核对:交易退券订单VS退券明细(券平台)VS营销账户流水核对;
3、券核销场景一致性核对:交易券订单 VS 券的核销明细 VS 营销账户流水记录。
二、核对规则
核对的维度:支付订单号+券号;
核对的指标:券的金额、券批次号、券号。
三、输出核对结果
需提供查询退券失败列表、券异常重试等接口供运营管理台调用;新增账证核对,核对结果为平账明细和不平账明细,提供给运营平台汇总展现,并将差错处理、异常处理情况给到运营平台。
四、异常修复、差错处理
针对识别的异常和差错,需要提供人工介入修复和处理能力。
4.7运营管理维度资金使用情况统计一致性
最终一致性不仅仅包含数据处理本身的一致性,还要保障对外、对内提供的数据展现的一致性。以券组合支付场景为例,运营展现的券资源使用情况与券资金消耗情况必须对其所有维度且保障一致性,避免出现由于资金统计口径的不一致出现偏差可能导致的资金调度的错误,带来资金管理层面的错误和风险。
5违反一致性设计原则的短款风险和规避措施
违反一致性设计原则,会造成非常多的问题和风险,其中短款风险是最严重的一种。本章节针对因违反一致性设计共性原则造成的短款风险,规避措施就一个,即严格遵照一致性设计原则,尤其是对“严禁”和“必须”类原则。
5.1违反“严禁可能导致短款的强制终态原则”的短款风险
违反本原则的场景,通常是在“强制终态”只会导致长款的预期场景下设计实现的,认为这样只会小概率导致VOC风险,并通过人工退款闭环。
可能造成短款的原因和建议措施:
第一, 一旦开了“强制终态”的口子,就可能因为BUG导致终态非预期,从而造成短款,即使得产生短款风险成了可能,建议措施就是严格遵守本原则不能“强制终态”;
第二, 可以通过其他手段应对“超时未知”的情况,例如重试(非换单)、主动查询交易结果、通过资金安全领域闭环处理等。
5.2违反“严禁架构元素自行采用数据库DML方式自行修复资金安全相关问题原则”的短款风险
违反本原则的场景,通常是想通过数据库DML数据修复手段应对架构元素或者软件单元之间信息交互的小概率丢失未达的异常情况。
可能造成短款的原因和建议措施:
第一, 数据库DML数据修复手段因为是直接作用于底层数据库数据层面,相对于联机处理逻辑,从逻辑严谨性、业务合理性、可测试性(QA)等各方面存在难以弥补的差距,通常是在资金安全领域做闭环处理时采用该种技术手段,不建议各个架构元素或者软件单元开发团队自行采用;
第二, 如果数据库DML数据修复手段导致影响了商户对账、商户清结算等,可能会导致给到商户的资金不准确,如果不准确恰恰是要“多”付给商户资金,而我们的资金动作又真的按照“多”出的结果进行了结算,就导致了事实上的“短款”。
5.3违反“必须架构元素一致性自闭环不信任原则”的短款风险
违反本原则的场景,通常是信任上游已经做过的一致性校验,而自身没有基于不信任做到闭环校验一致性,这样非常容易引发“短款”风险。
可能造成短款的原因和建议措施:
第一, 在支付业务领域,不能因为某个环节已经做了一致性校验,就要简化其他环节同类校验,因为金融领域都是围绕客户资金处理的,不允许任何疏忽和省略,而是要不嫌麻烦多环节自闭环一致性检查,做到尽可能多的环节严防死守,才能确保资金处理的正确性,尤其是短款风险的消减和消除。;
第二, 支付最核心的关键环节包括支付交易、支付核心(含支付账户)和支付通道,本原则规定至少这三个关键环节都要自闭环校验一致性,例如退款原单是否存在且原单中可退金额是否足够的校验检查,如果某个环节缺失该校验过程,一旦其他环节因为版本变更的BUG导致也没有正确校验,就会造成重复退、多退等情况,造成短款风险;
第三, 只要严格遵循本原则做到自闭环一致性检查校验,不相信上下游而是只相信自己,就可以基本规避此类短款风险。
5.4违反“必须逆向原单校验原则”的短款风险
违反本原则的场景通常是逆向交易,典型的是收单退款,结合上面的自闭环原则,即可基本规避此类场景的短款风险。
可能造成短款的原因和建议措施:
第一, 逆向交易本质上是依赖正向交易的存在性,所以在逆向交易过程中首先要检验原单的存在且精确匹配;
第二, 逆向交易是针对正向交易的逆操作,在正交易真实存在且精确匹配的前提下,需要进一步校验逆向操作的合理性,即通常不能超出正向交易的范畴,例如逆向交易的金额不能超过正向交易的金额;
第三, 逆向交易的原单校验要在架构元素或者软件单元做到自闭环,不能依赖外部上下游,具体描述参见自闭环原则相关描述;
第四, 严格执行本原则即可基本规避此类短款风险。
5.5违反“必须幂等避免资金或者资源重复处理原则”的短款风险
违反本原则的场景,通常是当上游因为某种原因多次重复调用,如果没有幂等保护,就会造成短款风险。
可能造成短款的原因和建议措施:
第一, 在出金场景下,如果在没有幂等保护的情况下重复执行,就会导致重复出金而造成短款,如果是入金则会造成因多次重复扣减客户资金而被投诉;
第二, 幂等保护本身需要确保容错能力和健壮性,避免幂等没有生效的情况下依然造成重复执行;
第三, 避免这类短款风险,必须严格执行本原则,同时要注意结合另外两条原则一起融入设计,即“必须不自动换单重试原则”与“尽可能幂等资金处理保护靠前实现原则”。
5.6违反“必须不自动换单重试原则”的短款风险
违反本原则的场景,通常是当第一次交易因为某种原因没有得到终态结果,例如下游返回超时导致结果“未知”,为获得终态结果而发起重试。
可能造成短款的原因和建议措施:
第一, 如果因为没有获取终态而发起原单重试,在下游进行幂等保护的情况下,通常是安全且能够满足需求的;
第二, 当下游因为某种原因幂等保护后的结果不满足预期的情况下,首先想到的就是换单重试,从业务本质上看就是由客户发起的“全新”交易请求,会成功绕开下游幂等保护,是相对危险和不可控的操作,容易造成短款风险,例如重复出金;
第三, 规避由此造成的短款风险,要求必须遵循本原则不能自动换单重试,不满足预期情况下可以采用主动查询获取交易终态结果,最差情况可以通过资金安全领域能力,例如异常识别、异常处理、差错处理等手段进行修正,在资金安全领域可以有“手动”的经过人工审核的“换单”重试来闭环。
5.7违反“必须接口业务状态判断原则”的短款风险
违反本原则的场景比较常见,最常见的是通过“错误码”返回上游来满足执行结果的判断,从而造成风险或者隐患。
可能造成短款的原因和建议措施:
第一, 业务状态定义和定位(职责所在)与错误码是有区别的,业务状态是纯粹的承载调用结果的“业务状态”本身,不具备其他含义,结果通常只有两种:成功或者失败;
第二, 错误码通常是用来标识错误的类型、原因等,通常承载的是定位问题、提升客户体验等的职责,当错误码反馈某种问题的时候,通常对应的业务状态会是“失败”,这也是二者通常被混用的原因;
第三, 错误码本身如果同时承载业务状态判断,存在一些缺点:(1)错误码取值是随着错误类型、错误原因等会迭代变化的,由此带来的对业务终态的逻辑判断也必须随之迭代变化,从而造成变更风险耦合;(2)错误码推到出业务终态是需要逻辑计算的,虽然计算规则通常不复杂,但是相对于直接的业务状态的“成功”或者“失败”的直接判断还是复杂的;(3)错误码的内容或者判断逻辑如果发生变化,通常只会影响错误码本身相关的质量风险,例如错误信息不准确,如果与业务状态耦合,则可能会导致业务终态判断失误,从而造成短款风险,例如扣款失败判断成扣款成功;
第四, 业务终态的另一个容易犯错的地方是主动查询业务状态的查询调用,需要明确“查询结果终态”与“被查询的业务状态的终态”且区分成两个来表达,避免混用造成短款风险;
第五, 规避由此造成的短款风险,要求必须遵循本原则设置独立的“简单、单一、直接”的“业务状态”来承载业务终态,不能通过错误码替代,也不能两个业务终态混用。
5.8违反“必须终态不可变原则”的短款风险
违反本原则的场景,在业务处理完成要记录“业务终态”的时候,没有去检查当前状态而直接写入。
可能造成短款的原因和建议措施:
第一, 如果在写入“业务终态”的时候不去检查当前状态,如果当前状态已经终态,无论与要写入的终态是否一致,都可能是严重问题。因为,业务终态是业务处理的重点,原则上有且只有一个业务处理流程能够走到业务处理的终点,出现这种情况就意味着很有可能针对同一个业务对象的业务处理出现了重复,如果是出金那么就存在短款风险;
第二, 如果遇到这种情况,一定要抛出异常,建议是严重异常,必须终止当前的业务处理过程,并通过针对性的异常处理完成闭环;
第三, 规避由此造成的短款风险,要求必须遵循本原则抛出异常、终止业务处理、针对性异常闭环。
5.9违反“必须出金预扣原则”的短款风险
违反本原则的场景,通常是并发出金相关业务处理,如果没有遵循本原则,则造成短款风险极高。
可能造成短款的原因和建议措施:
第一, 当多笔针对同一资金进行出金扣款并发执行时,如果不做预扣则会出现“幻读”造成超出原始资金的出金,从而造成短款风险。例如,针对一笔100元的收单交易,当一笔50元退款和一笔60元退款并发执行时,根据原单校验原则,不做预扣,则两笔退款的原单校验都发现可退金额是足够的,如果最终二者均成功,则发生了110元退款,已经超出原始订单金额100,造成短款;
第二, 从理论上,并发出金也可以通过锁定出金资金实现,但明显锁定机制大大限制了系统并发能力,不建议采用;
第三, 规避由此造成的短款风险,要求必须遵循本原则在出金时进行预扣避免。
5.10违反“必须旁路处理不能破坏一致性核心对象一致性原则”的短款风险
违反本原则的场景,通常是在发生某种异常或者差错需要资金安全领域相关能力接入进行修正或者补偿闭环或者发生在一些自动清理相关实现。
可能造成短款的原因和建议措施:
第一, 资金安全领域相关能力,例如异常识别和处理、交易稽核、差错处理等,都是在发现一致性出现问题的情况下进行修复和闭环,根据不同的场景向前走(让交易成功)或者向后走(让交易失败),但是修复和闭环不能干扰和破坏原交易一致性核心对象之间的一致性,例如银行卡收单在交易成功(核心对象为交易单)、核心失败(核心对象是支付单)、通道成功(核心对象为两联外部资金)的情况下,资金安全修复措施是通过调用核心提供的状态修复相关接口使得支付单为“成功”从而确保该笔银行卡收单最终呈现的业务状态为成功。在这个处理过程中,作为旁路处理的修复动作,必须基于正确判断规则和精准的一致性对象状态的识别才能做到不破坏一致性。如果这里的通道成功判断失误,则核心修复成成功,则本来不“危险”的不一致经过修复变成了产生短款风险的“危险”不一致,即交易单成功、支付单成功、两联外部资金失败;
第二, 规避由此造成的短款风险,要求必须遵循本原则在资金安全相关处理、自动清理等旁路处理中,确保不会破坏一致性核心对象间的一致性,产生新的一致性问题。
5.11违反“尽可能幂等资金处理保护靠前实现原则”的短款风险
违反本原则的场景,通常是幂等逻辑实现在业务处理逻辑的中后段,甚至是交易结果已经终态后再幂等,这种实现会造成因为某种原因(例如抛出异常)还没到幂等逻辑就处理结束了,甚至更严重的情况是业务处理逻辑执行完成形成新的终态后才到幂等逻辑执行,相当于幂等失效。
可能造成短款的原因和建议措施:
第一, 幂等靠后实现很可能导致幂等失效,如果是入金场景会造成长款导致VOC风险,如果在出金场景则会造成短款风险;
第二, 规避由此造成的短款风险,要求尽可能遵循本原则把幂等相关处理逻辑放在业务处理逻辑的前面,尤其是业务核心处理逻辑(完成后交易终态)之前,避免核心逻辑幂等保护失效。
5.12违反“尽可能不做强制终态原则”的短款风险
违反本原则的场景,通常是遇到下游返回超时,业务需求又要求业务要及时有终态,例如在用户体验方面要求必须在合理时间范围内给用户一个反映业务中台的反馈,这种情况下如果采用强制业务终态并及时反馈给用户的做法,就有可能造成短款风险。
可能造成短款的原因和建议措施:
第一, 当强制业务终态时,在出金场景下,如果强制成“成功”而实际未成功则造成VOC风险,如果强制成“失败”而实际成功则造成短款风险;反之在入金场景下,如果强制成“成功”而实际未成功则造成短款风险,如果强制成“失败”而实际成功则造成VOC风险;
第二, 建议尽量通过“处理中”、“超时”等反应客观实际的业务状态,如果确实要终态的场景则采用主动查询的方式获取实际的业务终态而不是通过强制终态实现,如果主动查询超过用户体验等业务需求容忍的极限范围,建议通过客户体验的一些变通措施应对。