39 生产案例:基于延迟消息机制优化大量订单的定时退款扫描问题示例代码

Posted 鮀城小帅

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了39 生产案例:基于延迟消息机制优化大量订单的定时退款扫描问题示例代码相关的知识,希望对你有一定的参考价值。

一、基于延迟消息机制优化订单退款扫描问题

1. 订单退款扫描的问题

之前写过一个电商小程序,在它的购物流程中,作为用户在小程序上都会先选择一些商品加入购物车,然后对购物车里选择的一些商品统一下一个订单,此时后台的订单系统必然会在订单数据库创建一个订单。

 当用户下了一个订单之后,在订单数据库里会有一个订单,订单的状态却是“未支付” 状态,因为此时用户还没有支付该订单,而订单系统也在等待用户完成该订单的支付。

这时就有两种可能了,一种可能是用户下单之后立马就支付掉了,那么接着订单系统可以走后续的流程,比如通过MQ发送消息通知优惠券系统给用户派发优惠券,通知仓储系统进行调度发货等。

另外一种可能就是用户下单之后,并没有马上支付该订单。

以淘宝、京东为例,实际情况中,存在有大量的用户每天回下很多订单,但是不少订单一直没有进行支付的。而无论是出于什么原因,这部分未支付的订单是占用了商品的库存量的。

所以一般订单系统都必须设置一个规则,用于在订单下单超过规定时间,比如30分钟或者24小时没有支付,就必须由订单系统自动关闭该订单,后续如果要购买该订单内的商品,就让用户重新下单。

2. 方案一:后台线程扫描

在订单系统开启一个后台线程,不停的扫描订单数据库里所有的未支付状态的订单,如果超过30分钟了还没支付,就自动将订单状态更新为 “已关闭” 。

 这种方案,在订单系统的后台线程要不停的扫描各种未支付的订单,在落地上是不建议使用的。

原因之一,是未支付状态的订单较多时,需要不间断的去扫描,可能每个未支付状态的订单扫描了N多遍后,才发现他已经超过30分钟没支付了。

另一个原因,是不能去分布式并行扫描订单。这是因为未支付订单过多,只开启一个线程必然效率低下,而要在多台集群部署扫描订单服务的话,却很难去为每台机器分配扫描的订单和方式。

3.最佳方案:延迟消息

所谓延迟消息,是说订单系统在创建一个订单之后,可以发送一条消息到MQ里去,我们指定这条消息是延迟消息,比如要等待30分钟之后,才能被订单扫描服务给消费到。

 当订单扫描服务在30分钟后消费到了一条消息之后,就可以针对这条消息的信息,去订单数据库里查询这个订单,看看它在创建后超过30分钟后,是否还是未支付状态?

如果此时订单还是未支付状态,就可以关闭订单;如果订单已经支付了,就什么都不用做了。

 4. 总结

基于延迟消息的方案要比用后台线程扫描订单的方式要好的多,一个是对每个订单你只会在它创建30分钟后查询一次而已,不会反复扫描订单多次。

另外就是当订单数量很多时,可以让订单扫描服务多部署机台机器,通过对MQ中的Topic可以指定多个MessageQueue,由每个订单扫描服务的机器作为一个Consumer去处理一部分订单的查询任务。

二、RocketMQ延迟消息的代码实现

 在上述的代码中,发送延迟消息的核心就是设置消息的 delayTimeLeve,也就是延迟级别。

RocketMQ 默认支持一些延迟级别如下: 1s 5s 10s 30 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h 。

上面的代码中,设置延迟级别为3,意思就是延迟 10s ,发送出去的消息,会过10s被消费者获取到。如果是订单延迟扫描场景,可以设置宴会级别为16。

以上是关于39 生产案例:基于延迟消息机制优化大量订单的定时退款扫描问题示例代码的主要内容,如果未能解决你的问题,请参考以下文章

基于rabbitMQ 消息延时队列方案 模拟电商超时未支付订单处理场景

37 生产案例:基于RocketMQ进行订单库数据同步的消息乱序问题及解决方案

基于redis的延迟消息队列设计

基于redis的延迟消息队列设计

基于消息队列(RabbitMQ)实现延迟任务

基于消息队列(RabbitMQ)实现延迟任务