延时队列
需求描述
场景一
在淘宝下了订单,过半个小时未支付就取消订单
场景二
还是淘宝(别问,问就是淘宝资深剁手党),发货后超过15天未确认就自动收货
需求分析
本质上都是超过xxx时间,就异步去做一件事。说到异步那基本上就是搞个定时任务去轮询或者消息队列+轮询。基本上有几种实现方式,挨个看一下。
实现方式
DelayQueue+Delayed
Java的并发包java.util.concurrent下提供了延时队列DelayQueue,它内部维护了一个优先级队列PriorityQueue来维护任务顺序,方便取出到时间的任务。PriorityQueue是个二叉堆,这就意味着它的插入、删除的时间复杂度都是O(logn)。
定时任务Quartz
Quartz是一个任务调度框架,不过它有一定的周期性,可能很多单子已经超时,但还没到达触发执行的时间点,那么就会造成订单处理的不够及时。如果对超时的时间精度要求没那么高的情况下可以使用。
Redis
Redis的Zset
Redis有种数据类型Zset,它利用score属性为集合内元素维护一个顺序,通过Zset就可以实现延时队列。
做法大概是:
- 任务插入的时候key是你的单号或者唯一ID,score是时间戳
- 异步去redis用zrange批量取出超时的单号,然后进行处理
Redis的发布订阅功能
Redis也提供了发布订阅功能,可以修改配置文件redis.conf中的:notify-keyspace-events Ex,监听超时的key,然后编写监听器处理。
RocketMQ
RocketMQ的延迟消息机制
RocketMQ提供的延迟消息机制。如果往RocketMQ发送了一条延迟消息,它不会立刻对消费者可见,而是在指定的时间后再投递给消费者。那么我们可以给RocketMQ投递延迟消息,然后到时间去