关于java:钱被扣走了但是订单却未成功支付掉单异常最全解决方案

42次阅读

共计 3322 个字符,预计需要花费 9 分钟才能阅读完成。

前言

好了,回归到明天的主题,明天分享一下领取零碎中异样一些解决形式。

其实这些解决形式并不只是局限于领取零碎,也能够实用于其余零碎,大家能够借鉴,利用到本人零碎中,进步本人零碎的健壮性。

异样是零碎运行不可避免会产生的问题,如果所有都失常,咱们的零碎设计将会相当简略。

然而惋惜没有人能做到这一点,所以为了解决异样可能导致的问题,咱们不得不须要加上很多额定的设计,用来应答这些异样。

能够说零碎设计中,异样解决须要咱们着重思考,将会占据咱们大部分的精力。

上面咱们先来看下领取零碎中最常见的异样:掉单

欢送关注我的公众号:程序通事,取得日常干货推送。如果您对我的专题内容感兴趣,也能够关注我的博客:studyidea.cn

掉单异样

一个最常见的领取平台架构关系如下所示:

上图咱们是站在第三方领取公司领取角度,如果是本人公司的外部领取零碎,那么内部商户这一块其实就是公司外部一些零碎,比如说订单零碎,而内部领取渠道其实就是第三方领取公司

咱们以携程为例,在其下面发动一笔订单领取,将会通过三个零碎:

  1. 携程创立订单,向第三方领取公司发动领取申请
  2. 第三方领取公司创立订单,并向工行发动领取申请
  3. 工行实现扣款操作,返回第三方领取公司
  4. 第三方领取实现订单更新并返回携程
  5. 携程变更订单状态

下面的流程,简略如下图所示:

在这个过程就可能会碰到,用户工行卡曾经扣款,然而携程订单却还是待领取,咱们通常将这种状况称为 掉单

上述掉单的场景,少数是因为 ③、⑤ 环节信息失落导致,这种掉单咱们将其称为 内部掉单

还有一种极少数的状况,收到 ③、⑤环节返回信息,然而在 ④、⑥ 环节外部零碎更新订单状态失败,从而导致失落领取胜利的信息,这类掉单因为是外部问题,咱们通常将其称之为 外部掉单

内部掉单

内部掉单是因为没有收到对端返回信息,这种状况极有可能是网络问题,也有可能对端解决逻辑太慢,导致我方申请超时,间接断开了网络申请。

减少超时工夫

对于这种状况,第一个最简略的解决办法,适当的减少超时工夫

不过这里须要留神了,在咱们减少网络超时工夫之后,咱们可能还须要调整整个链路的超时工夫,不然有可能导致整个链路外部差事从而引起外部掉单。

画外音:对接内部渠道,肯定要 设置网络连接超时工夫与读取超时工夫

接管异步告诉

第二个方法,接管渠道异步回执告诉信息。

一般来说,当初领取渠道接口咱们都能够上送一个异步回调地址,当渠道端解决胜利,将会把胜利信息告诉到这个回调地址上。

这种状况下,咱们只须要接管告诉信息,而后解析,再更新外部订单状态。

这种状况下,咱们须要留神几点:

  1. 对于异步申请信息,肯定须要对告诉内容进行签名验证,并校验返回的订单金额是否与商户侧的订单金额统一,避免数据透露导致呈现“假告诉”,造成资金损失。
  2. 异步告诉将会发送屡次,所以异步告诉解决须要幂等。

掉单查问

有的渠道可能没有提供异步告诉的性能,只提供了订单查问的接口,这种状况下,咱们只能应用第三种解决办法,定时掉单查问。

咱们能够将这类超时未知的订单的独自保留到掉单表,而后定时向渠道端查问订单的状态。

若查问胜利或者明确失败(比方订单不存在等),能够更新订单状态,并且删除掉单表记录。

若查问仍旧未知,这时咱们须要期待下次查问的后果。

这里咱们须要留神了,有些状况下,有可能无奈查问返回订单的状态,所以咱们须要设置订单查问的最大次数,避免有限查问节约性能。

对账

最初,极少数的状况下,订单查问与异步告诉都无奈获取的领取后果,这就还剩下最初一种兜底的解决办法,对账。

如果第二天渠道端给的对账文件有这一笔领取后果,那么咱们能够依据这个记录更新间接更新咱们外部领取记录。

之前小黑哥写过一篇对账文章,感兴趣的能够再看一下:聊聊对账零碎的设计方案

画外音:稳当一点,能够先发动查问,而后依据查问后果更新订单记录。

不过有些极其状况,查问无奈获取后果,那么间接更新外部记录即可。

那如果第二天也没有这笔记录的后果,这种状况下,咱们能够认为这笔是失败的。如果用户被扣款,渠道端外部将会发动退款,将领取金额返回给用户。所以这种状况能够无需解决。

外部掉单异样

领取公司外部订单关系

接下来咱们讲下外部掉单异样,首先咱们来看下为什么会产生外部掉单的异样,这其实跟咱们零碎架构无关。

如上图随所示,第三方领取公司外部表通常为领取订单与渠道订单这样一种 1 比 N 的关系。

领取订单保留着内部商户零碎的订单号,代表第三方领取公司外部订单与内部商户的订单的关系。

而渠道订单代表着第三方领取公司与内部渠道的关系,其实对于内部渠道零碎来讲,第三方领取公司就是一个内部商户。

为什么须要设计这种关系那?而不是应用上面这种 1 对 1 关系的那?

如果咱们应用上图 1 对 1 的订单关系,如果第一次领取领取失败,内部商户可能会再次应用雷同订单号对第三方领取公司发动领取。

这时如果第三方领取公司也拿雷同的外部订单去申请内部渠道零碎,有可能内部渠道零碎并不反对同一订单号再次申请。

那其实咱们也有其余方法,生成一个新的外部单号,更新原有领取订单上外部记录,而后去申请内部渠道零碎。然而这样的话就会失落上次领取失败记录,这就不利于咱们做一些预先统计了。

那其实第三方领取公司也能够不反对雷同的订单号再次发动申请,然而这样的话,就须要内部商户从新生成的新的订单号。

这样的话,第三方领取公司是零碎是简略了,全副复杂度都交给了内部商户。

然而事实的状况,很多内部商户并不是那么容易更换生成新的订单号,所以个别第三方领取公司都须要反对同一内部商户订单号在未胜利的状况下,反对反复领取。

在这种状况下,就须要咱们下面的 1:N 的订单关系图了。

外部掉单异样的起因

当咱们收到内部渠道零碎的胜利的返回信息,胜利更新了渠道订单表的记录。然而因为渠道订单表与领取订单表可能不是同一个数据库,也有可能两者并不在同一个利用中,这就有可能导致更新领取订单表的更新失败。

因为领取订单是表保留着内部商户订单与外部订单关系,领取订单未胜利,所以内部商户也无奈查问失去胜利的领取后果。

此时渠道订单表曾经胜利,所以下面内部掉单的办法并不实用外部掉单。

外部掉单异样解决办法

第一种解决办法,分布式事务。

外部掉单异样,说白就是因为领取订单表与渠道订单表无奈应用数据库事务保障两者同时更新胜利或失败。

那么这种状况下,咱们其实就须要应用分布式事务了。

不过咱们没有采纳这种分布式事务,一是因为之前开发的时候市面上并没有开源成熟分布式事务框架,第二本人本人开发难度又很大。

所以对于分布式事务这一块,并没有什么应用教训。如果有应用分布式事务解决这类的问题同学,留言去能够评论一下。

第二种解决办法,异步弥补更新。

当产生外部掉单的状况,即更新领取订单失败等状况,能够将这里领取订单保留到一张外部掉单表。

然而这里可能会有一个问题,咱们无奈保障保留到外部掉单表这一步骤也肯定胜利。

所以说,咱们还须要定时查问,查问一段时间内领取订单未胜利,而渠道订单表已胜利的领取订单记录,而后也将其插入到外部掉单表。

另一个零碎利用,只须要定时扫描外部掉单表,将领取订单胜利,而后再删除外部掉单记录即可。

这里须要留神了,当领取订单表数据量很大之后,定时查问可能会慢,为了避免影响主库,所以这类查问能够在备库进行。

总结

明天次要介绍了领取零碎中的掉单异样,这类异样往往会导致用户理论曾经被扣钱,然而商户订单还是期待领取的状况。

这个异样如果没有很好解决,将会导致客户用户体验很不好,还有可能收到客户的投诉。

掉单的异样,通常能够内部零碎与外部零碎。而大部分的掉单都是因为内部零碎导致,咱们能够减少超时工夫,掉单查问,以及承受异步告诉解决 99% 的问题,剩下 1% 的掉单只能通过次日的对账来兜底。

外部零碎导致掉单异样是典型的分布式环境数据一致性的问题,这类问题咱们能够不须要谋求强一致性,只有保障最终一致性即可。咱们能够应用分布式事务解决这类问题,也能够定时扫描状态不统一的订单,而后在做批量更新。

最初,这次只是介绍领取零碎中一类掉单异样,下一篇文章中,再给大家介绍一下领取零碎的其余异样,敬请期待!

参考资料

  1. 知乎 @天顺 谈谈异样(一)

欢送关注我的公众号:程序通事,取得日常干货推送。如果您对我的专题内容感兴趣,也能够关注我的博客:studyidea.cn

正文完
 0