背景
用户下单,实现订单超时自动取消的机制。
下面也是针对要达到以上目的所要采用了一些常见方案探讨
方案一:定时任务
时序图
步骤
- 用户下单后,server端将订单数据进行存储;
- server端会有一个类似死循环的任务,每间隔N秒时间就到DB中进行查询,将状态还处于非终态的订单进行超时判断。
说明
- 上面这个方案应该算是最简单的一个方案了,间隔时间N根据具体业务场景所需要的情况来,但采用上面的这个方案也是有利有弊的。
优点
- 方案简单,实现复杂度低;
- 不用额外引入服务;
缺点
- 该方案适用于那些小而简单的项目;
- 如果开启多副本,还需要考虑选主机制;
- 如果订单数据量大会额外增加系统和DB负担;
- 时效性差,因为是串行执行,循环间隔时间N是固定的,所以具体的失效延迟受限于具体的订单量大小;
方案二:懒加载
时序图
步骤
- 在方案一的基础之上,增加了用户查询事件触发的机制,如果server端发现订单已经超时则直接更改订单状态;
说明
这个方案算是方案一的一个优化点,相对方案一而言,可以在轮询时间间隔N上,将N的时间延长,比如之前每隔1秒,后面可以改为每隔10秒等,从而降低了对DB的负载。但是如果在订单量大的情况下依然有时效性的问题,且会直接影响到商家在某个商品的库存量,所以这个方案也需要根据实际的业务场景来决定是否采用。
方案三:任务调度
时序图
步骤
- 在储存完订单的同时,也一并向任务调度服务注册一个延迟回调任务;
- 待时间到达后scheduler服务就触发一个回调事件;
说明
优点
- 时效性相对方案一二而言要高很多,它是直接针对的单个订单;
- server服务可以直接多开副本,不会导致重复消费的问题
缺点
- 对任务调度服务scheduler而言要求也要高一些,因为我们知道,常见的任务调度服务是只支持类似于crontab这种表达式的定时调度任务,而不是延迟调度任务,所以这个方案有个前提条件就是scheduler要支持延迟调度才行,要实现的话常见实现方式就是引入时间轮
方案四:延迟队列
在方案三的基础之上,我们可以直接引入消息队列MQ来替换scheduler服务,达到处理延迟消息的目的,但是目前市面上能支持定时消息和延迟消息的MQ不多:
从上图可以知道,开源产品钟只有阿里的RocketMQ支持定时延迟消息,且是固定的18个level。固定level的含义是延迟是特定级别的,比如支持3秒、5秒的level,那么用户只能发送3秒延迟或者5秒延迟,不能发送8秒延迟的消息。消息队列RocketMQ的阿里云版本(收费版本)才支持到精确到秒级别的延迟消息(没有特定Level的限制)。
上图是CMQ中对MQ功能的对比,其中标明腾讯的CMQ支持延迟消息。
在使用上,进一步到CMQ官网查看到以下信息
可知在延迟范围以及条数上都是有一定约束的。RocketMQ官网的表明付费的使用范围相对宽松一些
总结
上面提到的几个方案带有一定随意性,但相信还是能给你带来一些启发的,具体还是根据自身项目来采用不同的方案,同时在根据这些方案进行一些优化。
文章评论