让你实现一个订单超时取消功能,怎么设计?

Sherwin.Wei Lv7

让你实现一个订单超时取消功能,怎么设计?

一般会通过定时任务或者消息队列的延迟消息来实现订单超时取消功能。

定时任务

定时任务的逻辑就是扫描已创建未支付的订单,判断订单的创建时间与当前时间的差值,如果已经超过了预设的超时时间,比如 10 分钟,那么就将订单状态更新为已取消。

比如可以每 1 分钟扫描一次表,直接根据当前时间和超时时间得到筛选的时间,比如当前是 14:00,那么 13:50 分之前创建的订单未付款其实都超时了,将这个时间和状态作为查询条件进行数据库查询,得到超时的订单,最后批量更新超时订单的状态。

通过时间+状态查询效率会更高,如果直接通过状态查询,然后在内存中判断时间,其实会有很多订单是还未过期的,这样效率就比较低。

并且需要限制每次查询的数量,比如一次 limit 200。

一般会采用分布式定时任务框架,例如 xxljob 等,如果涉及多机任务并发执行提升效率的情况,需要对订单进行分片,比如机器1 处理订单号 % 2 余 0、机器 2 处理订单号 % 1 余 0 的订单等等。

定时任务方案的缺点是超时时间比较不准确,如果 1 分钟执行一次任务,那么相差的时间可能就是一分钟,如果订单量很大的情况可能还会放大不准确的时间,因为任务处理也需要花费时间,且对数据库压力也会比较大,因为会集中扫表。

消息队列

消息队列例如 RocketMQ 会提供延迟消息功能,仅需在下单的时候发送一条延迟 10 分钟取消订单的消息。

10 分钟后,消费者会接受到这条消息,如果这条订单还未支付则取消订单,若已支付则忽略这条消息。

可以看到这种方案不会对数据库产生压力,因为消息队列本身天然实现削峰填谷,消费者可以按照自己的能力来把控消费速率,并且可以横向扩展,通过加机器的方式加快消费速度。

相对而言超时时间的控制能更精确,且对系统压力不大。

其它的还有可以利用 redis zset 来实现,score 设置为订单创建时间+超时时长,订单号为 member,这样就可以通过 score 排序,找到超过当前时间的订单,进行判断就好了。

Comments
On this page
让你实现一个订单超时取消功能,怎么设计?