资金损耗是如何产生的?
支付系统对技术的考量有两点:
1、技术对提供服务的稳定性
2、资损的避免
这类问题通常只会导致系统使用慢,用户体验不好和投诉的情况
由于人为操作不当或者系统逻辑错误导致的资金损失,这都属于资金损失。
这时候通知了商户系统支付成功了,那商户发货了就会导致资金损失。
可能引发资金损失的技术问题:
1、网络异常问题:
接口一旦发生网络异常,这时候支付系统并没有达到最终状态,
网络异常会走Exception的catch处理,catch一般会走失败分支。
但银行侧最终的状态可能是成功、失败或者处理中,
如果银行侧最终成功,但商户侧被告知是失败,这样商户就会再次发起支付,就可能造成了重复付款。
修正方案,当用到网络支付的异常返回时,将订单设置为处理中的状态,然后等待定时查询或者通知,来返回最终状态即可。
2、查询和通知问题:
支付接口一般包括了交易接口、主动查询接口和异步通知接口。
查询接口一是用来查询非实时返回最终状态的订单结果,二是用来核对查询,
第一种查询失败或者查询异常,并不代表最终交易状态就是失败的,特别是第三方交易接口,这个查询失败指的是查询本身失败而并不是交易失败。
第二种查询速度过快,比如支付5秒之后立即去查询,但是没有此订单,可能是支付系统的处理链路较长,建议过一会再查询或者支付后立即发起查询的时间间隔设置远一些。
3、接口幂等问题:
接口可能隔天返回的状态不同,
当无法保证别人系统健壮性的问题,那么就保证自己系统健壮性。
上游订单流水号作为唯一索引做幂等,比如接口请求没有响应,以唯一订单流水号再次发起请求重试。
这样既保证了安全,又满足了继续发起请求的流程。
前后通知不一致的问题,如果第一次通知是准确的,就以第一次为主,如果第二次状态不一致,那么就进行人工预警,人为干预。 否则容易发生重复发起的情况
4、状态同步问题:
4、并发问题:
并发导致的重复支付
定时器问题,可能某时刻任务阻塞,两次任务造成了并发。这种情况需要控制定时器的任务状态,
还可以控制状态机来控制任务的状态
重试问题:
各种重试机制导致的重复支付,
比如MQ,Nginx,Http都有重试机制,
各种中间件的retry机制都会导致订单重复支付,
防止这种情况可以用到,前后端防重,
前端,JS禁掉提交按钮
后端,数据库加索引,redis加锁,token校验等等
后端最简单的方式:数据库乐观锁 + 有限状态机 + 白名单
状态机,有限个状态之间的转移和动作等行为的数学模型,状态的管理和状态的驱动。
支付系统中,状态的流转控制,可以避免订单被错误的执行或重复执行,
比如成功的状态不允许变更为处理中,
已发送的状态不允许被再捡起支付等
事后止损:实时监控系统
閱讀更多 老曹漫談 的文章