这个方案主要流程跟定时方案类似,主要区别在于第四步,第五步,第八步。
第四步的流程从插入掉单表变更为往延迟队列发送掉单消息。
第五步,补单程序接收掉单消息,然后触发支付掉单查询。
第八步,如果第七步支付结果查询为以下状态:
支付结果为扣款成功
支付结果为明确失败
掉单记录查询达到最大次数
补单程序将会告知延迟队列消费成功,延迟队列将会删除这条掉单消息。
其他状态将会告知消费失效,延迟队列将会在一定延时之后,再次发送掉单消息,然后继续重复第五步。
延迟队列这里的延迟队列需要自己实现,复杂度还是比较高的,这里给大家推荐几种实现方案:
第一种,基于 Redis SortedSet 实现延迟队列。可以参考一下有赞的实现方案https://tech.youzan.com/queuing_delay/
第二种,基于时间轮算法(TimingWheel)实现延迟队列,具体可以参考 Kafka 延时队列。
第三种,基于 RocketMQ 延迟消息。
前两种方案说起来还需要再开发,所以还是比较复杂的。
这里重点说下第三种方案,该方案是 RocketMQ 已经支持的特性,开箱即用,使用起来还是比较简单的。
RocketMQ 延迟消息支持 18 个等级,分别如下:
1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h消息发送方可以通过以下方式指定延迟等级,对应上方的延迟时间。
Message#setDelayTimeLevel消息消费方,如果消费失败,默认将会在消息发送方的的延迟等级基础上加 1。如果消息消费方需要指定其他的延迟等级,可以使用如下方式:
ConsumeConcurrentlyContext#setDelayLevelWhenNextConsumeRocketMQ 延迟消息,支持的特性还是比较基础、简单,不支持自定义延迟时间。不过对于掉单补偿的这个场景刚好够用,但是如果需要自定义延迟的,那还是得采用其他的方案。
方案优缺点延迟消息的方案相对于定时轮询方案来讲:
无需再查询全部订单,效率高
时效性较好
不过延迟消息这种方案,需要基于延迟队列,实现起来比较复杂,目前开源实现也比较少。
小结支付掉单、卡单是支付过程中经常会碰到的事,我们可以采用异步补偿的方案,解决该问题。
异步补偿方案可以采用如下两种:
定时轮询补偿方案
延迟消息补偿方案
定时轮询补偿方案实现起来比较简单,但是时效性稍差。
而延迟消息补偿方案总体来说比较优秀,但是实现起来比较复杂。如果没有自定义的延迟时间的需求,可以直接采用 RocketMQ 延迟消息,简单快捷。
另外延迟队列使用场景还是比较多,不仅仅能用在掉单补偿上,还可以用于支付关单等场景。所以有能力开发的团队,可以开发一个通用的延迟队列、
好了,今天的文章就到这里了。
我是楼下小黑哥,下篇文章再见,886~
欢迎关注我的公众号:小黑十一点半,获得日常干货推送。如果您对我的专题内容感兴趣,也可以关注我的博客:studyidea.cn
历史支付文章推荐钱被扣走了,但是订单却未成功!支付掉单异常最全解决方案
一笔订单,但是误付了两笔钱!这种重复付款异常到底该如何解决?
收款神器!解读聚合收款码背后的原理|原创
手机没网了,却还能支付,这是什么原理?|原创
轻轻一扫,立刻扣款,付款码背后的原理你不想知道吗?|原创
支付渠道路由系统进化史
从零开始设计对账系统
微信支付宝接入大全
多支付通道路由网关设计
银行卡支付,背后到底发生了什么?
欢迎关注我的公众号:小黑十一点半,获得日常干货推送。如果您对我的专题内容感兴趣,也可以关注我的博客:studyidea.cn