美文网首页
支付系统资金风险的一些事

支付系统资金风险的一些事

作者: lucode | 来源:发表于2020-02-11 09:47 被阅读0次

    极客时间每日一课笔记

    • 资损的产生有哪几种场景?

    • 技术人员如何避免,以及事后哪些解决办法呢?

    对于支付系统的考量,技术侧看两个指标

    1. 系统能够提供服务的稳定性

    可能的原因是:

    cpu飙升导致的服务响应速度慢,内存溢出,线程数不可控制,以及慢接口导致的连接池不可用等等。

    这一点问题最多造成的是用户体验不好或者用户投诉而已

    1. 系统发生资金损失
    如何来定义资金损失?

    在金融支付系统中,由于人为操作不当或者系统逻辑错误导致的资金损失,这都属于资金损失。

    举个例子,在一个支付收单系统。中间是支付平台,上游商户系统,下游是银行或第三方系统。如果支付系统在未明确受到下游支付的成功,而通知上游支付成功了或者支付失败,有可能导致上游发货和上游再次重置支付。一个真实的案例支付系统,因为对并发场景的处理不当导致重复支付1000多万。有人可能会说损失可以通过法律的途径追回来,但真实情况是这1000多万用户太过于分散,企业追回的成本太高。

    可能发生资损的场景

    支付功能(比如:单笔代收付、批量代收付、快捷支付、扫码支付等),清结算功能,提现功能,退款功能,记账模块功能等这些环节都可能发生资损。

    常见的问题如下

    • 网络异常问题
    • 查询和通知问题
    • 接口幂等问题
    • 状态同步问题
    • 并发问题
    • 定时器问题
    • 提交表单问题
    • 重试问题

    如何避免和解决资损问题

    网络异常问题

    网络异常问题经常出现在支付系统每次调用银行系统后,接口一旦发生网络异常,这时候支付系统并没有拿到最终状态,但是商户侧异常捕获之后直接定为失败的终态,其实银行侧最终状态可能是成功,但是用户却被告知失败,可能再次发起重试,这样就造成了重复付款。

    这种系统调用的网络异常通常包括了

    • Connection Reset
    • Connection Refused
    • Connection Timeout
    • The target server failed to respond
    • Socket Read Timeout

    遇到这一场景的时候,把订单设置为处理中状态,然后等待你的定时任务主动查询或者支付回调再次通知,达到最终状态即可。

    查询和通知问题

    支付接口一般包括了交易接口,主动查询接口和异步通知接口。

    常见的问题有以下四种

    • 查询失败或者异常

    订单结果查询失败或者异常并不代表这笔订单最终是失败,特别是第三方查询交易接口返回的响应码状态就是失败,这时候开发人员一定要明确这是订单查询操作本身失败并不是交易失败。如果这时候粗心(没认真看文档)导致把订单的最终结果设置失败,那么就可能引发重复支付的问题。

    • 查询频率过快

    为了保证支付订单能够最快的到支付结果,我们会在系统的交易请求之后,比如说快速的15秒之内发起主动查询,那结果呢,第三方系统返回无此订单,同时支付平台返回也无此清单给商户,这时候导致商户系统又发生了第二次的支付请求,实际上这种问题经过最后的排查得知,第三方系统由于处理请求的链路比较长,只是说不允许那么快发起交易,建议在两分钟之后再来查询,如果两分钟之后查询再返回上有无此订单,虽然说这种问题非常极端,但是我们也是会遇到.

    • 被查询接口幂等性问题

    案例

    T日的订单已经有了最终状态,因为某种特殊的业务场景,运营人员手工操作,把这笔订单从最终状态修改成了处理中,因为人员认为系统有查询接口可以再次查回来,结果实际情况是什么呢?银行系统T+1日返回了不一样的订单状态,结果导致这个商户接受这个错误状态之后又发起了再次支付,是因为银行在T+1日,这笔交易发生了撤回失败,返回的状态是想告诉大家,这是撤回失败的状态,由于这样导致了状态不一致。但这个故事在运营商的同学理解来看,银行的接口应该每次查询都返回同样的状态才对啊。

    其实这个东西从本质来说,也可以是一个接口幂等性的问题,对于这个问题建议的方案是说如果我们没有办法保证别人系统兼容性的问题,那我们可以保证我们的系统兼容性。

    • 异步通知

    我们经常会遇到上游或者下游重复通知的问题,并且甚至有可能遇到前后两次通知不一致的情况,这种东西在某些支付公司的接口中可能遇到过,这种极少的情况也不能忽略,建议处理方式是第一次通知的结果是准确的,一定会以第一次结果为准,如果第二次通知发生结果规则情况这时候还是以第一次为主,那这个状态呢进行预警人为干预,否则的话那么就容易发生重复发起的情况。

    • 下单接口幂等性
      只有做到幂等方才可进行后期的重试。对于处理重复提交的情况办法是上游订单流水号作为唯一幂等条件。比如说在数据库订单号重复的时候抛出异常,再去查询那个之前的支付结果。除此之外,还可以在请求的入口处用 redis 防重复。

    状态同步问题

    前面讲过,支付系统最终状态完全依赖于下游系统。但是每家系统返回的报文都有差异,有些系统则响应码和详细信息比较复杂,在我以往的经验中,根据订单状态及时响应码是一件非常重要的事情,总结一下最佳实践。

    • 对于查询接口返回订单不存在的情况,需要单独设置错误码做特殊报警处理,付款类的交易不可以设置为失败状态,这样才可以避免资金的重复支付。

    • 资金类的交易订单设置的状态是根据第三方报文来设置的,更新状态需要采用保守的策略,对于不确定的状态不可以直接就用他的失败。这样也可以避免资金的重复支付。

    • 硬件服务器年久失修,导致崩溃有时候 redis,mq,正在处理中的瞬时的内存状态就会丢掉服务器的启动之后,状态如果处理不当,也会导致再次重复处理。

    并发问题

    • 集群环境下两个同样的服务并发导致的
    • 机器人何为操作导致并发
    • 定时任务并发执行的

    表单重复提交问题

    比如用户连续点击了两次取消按钮或者用户提交表单的时候。因为网速过慢,又点击了一次,这样的并发都会导致重复提交问题。

    定时器重复执行

    定时任务一般会和项目工程在一起,容易被部署在多个服务器集群累。或者遇到过定时器浪打浪的问题,比如说我的定时器两分钟执行一次,由于某种异常,比如说线程阻塞连接超时响应超时等,第一轮定时器还没有执行完成,第二轮定时器启动之后,那就重复执行了这种问题。需要控制定时任务的状态,或者使用状态机来控制所处理的订单状态。

    各种重试机制问题

    很多情况还是中间件出现的各种重试导致的,如果开发人员不明白里面的原来很难排查出来。比如 http 的重试,各种中间件的retry机制都会导致订单重复支付。

    如何防重

    前端大概就是,有 Token 校验,js 禁用提交按钮等等
    主要是后端 这里有这样子一个方案 数据库乐观锁,有限状态机,白名单

    有限状态机即又称为自动机简称状态机,表示有限个状态,在这些状态之间的转移和动作等行为的数学模型。

    这里的重点是状态的管理和状态的驱动,在支付系统中状态的流转的控制可以避免订单被错误的执行和重复执行。
    比如成功的状态不允许被变更为处理中,已发送的订单状态不允许被捡起支付等。
    具体的解决方案如下,如果当前的订单处于路由成功的状态,那我们为了避免定时任务和人工并发执行,只需要如图这样的一段非常简单的代码,我们来解析下这段代码在这段代码里。数据库乐观锁来控制并发白



    数据库乐观锁来控制并发白名单,控制状态机的流转必须是白名单机制,不可以是黑名单机制。白名单告诉我们,只有15的状态才会允许更新为63或者60,否则更新失败。

    其他风险

    • 运营人员产线配置
    • 运维人员修改系统基础参数

    机制流程,实时监控,总之来说事前避免,事中监控,墨菲定律告诉我们该发生的是比会发生,所以还需要做到事后止损。

    本文由博客一文多发平台 OpenWrite 发布!

    相关文章

      网友评论

          本文标题:支付系统资金风险的一些事

          本文链接:https://www.haomeiwen.com/subject/utvtfhtx.html