java延时队列简单介绍

背景

在业务发展过程中,会出现一些需要延时处理的场景,比如:

a.订单下单之后超过30分钟用户未支付,需要取消订单 b.订单一些评论,如果48h用户未对商家评论,系统会自动产生一条默认评论 c.点我达订单下单后,超过一定时间订单未派出,需要超时取消订单等。。。 处理这类需求,比较直接简单的方式就是定时任务轮询扫表。这种处理方式在数据量不大的场景下是完全没问题,但是当数据量大的时候高频的轮询数据库就会比较的耗资源,导致数据库的慢查或者查询超时。所以在处理这类需求时候,采用了延时队列来完成。

几种延时队列

延时队列就是一种带有延迟功能的消息队列。下面会介绍几种目前已有的延时队列:

Java中java.util.concurrent.DelayQueue

优点:JDK自身实现,使用方便,量小适用 缺点:队列消息处于jvm内存,不支持分布式运行和消息持久化

Rocketmq延时队列

优点:消息持久化,分布式 缺点:不支持任意时间精度,只支持特定level的延时消息

Rabbitmq延时队列(TTL+DLX实现)

优点:消息持久化,分布式 缺点:延时相同的消息必须扔在同一个队列

Redis实现的延时消息队列适合的项目特点:

    Spring框架管理对象 有消息需求,但不想维护mq中间件 有使用redis 对消息持久化并没有很苛刻的要求

Redis实现的延时消息队列思路

Redis由于其自身的Zset数据结构,本质就是Set结构上加了个排序的功能,除了添加数据value之外,还提供另一属性score,这一属性在添加修改元素时候可以指定,每次指定后,Zset会自动重新按新的值调整顺序。可以理解为有两列字段的数据表,一列存value,一列存顺序编号。操作中key理解为zset的名字,那么对延时队列又有何用呢?

试想如果score代表的是想要执行时间的时间戳,在某个时间将它插入Zset集合中,它变会按照时间戳大小进行排序,也就是对执行时间前后进行排序,这样的话,起一个死循环线程不断地进行取第一个key值,如果当前时间戳大于等于该key值的socre就将它取出来进行消费删除,就可以达到延时执行的目的, 注意不需要遍历整个Zset集合,以免造成性能浪费。

经验分享 程序员 微信小程序 职场和发展