首页 > 背就完事了-重复支付问题完美方案(以12306为例)
头像
程序员辰星
发布于 10-12 09:48 四川
+ 关注

背就完事了-重复支付问题完美方案(以12306为例)

背景

什么情况下会出现重复支付问题呢?我们再看下支付流程:

当用户发起了支付请求后,12306发起对三方支付的请求,但支付的结果回调一般需要几秒;没有耐心的用户这个时候可能在支付页面再次发起支付请求,造成重复支付。

解决方案及逐字稿

前端处理

用户一旦点击网上支付后,应该将此按钮置灰(锁定按钮,无法再点击)

后端处理

为了防止部分用户通过调用接口的方式频繁支付,对于后端,也需要进行兜底。理论上这就是一个防重复的幂等问题。根据前面讲到的支付流程,有两种处理方案。

三方支付保障幂等

如果支付宝、微信等三方支付能够处理对同一笔请求的幂等,12306这边就变得简单了,通过用户ID+车次ID+出发站+始发站+出发时间生成唯一流水号,发起支付请求时,将该流水号带给三方支付,支付方就可以通过唯一流水号来做支付的幂等。

12306端的幂等(没那么简单!)

反倒如何三方支付没有做这类幂等性的保障(基本不可能没有,但我们要做兜底),我们就需要做幂等的保障了。大部分通过在讲幂等,都是在讲通过一个幂等标识判断就可以了,而实际上这里面其实大有文章!

初步方案(加一个幂等标识)

那很多同学,可能在网上了解过,幂等问题的解决方案,支付成功了,加个标识不就好了吗,每次发起支付时,都先判断标识是否存在。

演进(标识先行)

其实这样问题是一样的,支付的成功回调,需要一定的时效性,等成功回调后再加标识,这个时候用户可能又发起了支付

对于幂等判断来说,标识的成功添加至关重要;所以,标识应该先添加,再做业务的处理。新的处理流程如下:

可能有注意到,我在当判断标识已存在的情况下处理,打了个问号? 有些同学,可能不太理解为什么?标识存在,就代表已支付,不做任何处理不就行了吗?(too young,too simple!)

我们在支付失败的时候,删除标识。标识存在,不代表这个时候已经支付成功,可能成功,也可能还在处理中。

答:只能回查三方支付方,一般通过接口调用的发送,都会有一个唯一流水号,通过流水号回查渠道方是否真的处理成功。那么新的流程图,演变为:

还得演进!!!

其实这里还有一个问题,为了保障绝对幂等,标识没有过期机制。就会导致redis容量越来越大,怎么办呢。有的同学说,把已支付成功的标识删除了就好了。

问题是,现在的标识完全没有状态区分,根本没法判断是处于支付中还是已支付。所以,对于标识我们还得加入一个消息状态的流转。

新的流程图:

而对于key的清除,可以采用:

redis监控-》内存告警-》监控平台配删除策略-》支付成功的删掉

12306项目亮点面试话术全梳理

我将12306所有涉及的核心问题,都整理的面试话术,欢迎大家订阅专栏星球上的项目主要讲了12306的基本问题, 比如车票搜索、下订单、三方支付的对接、分库分表、缓存一致性等;但比如写扩散问题、最短换乘问题、候补购票实现方案、如何筛选相邻座位算法优化、灰产问题、12306的真实架构分析等等是没有涉及到的

全部评论

(2) 回帖
加载中...
话题 回帖

近期热帖

热门推荐