灵感来袭,基于Redis的分布式延迟队列(续)

背景

上一篇(灵感来袭,基于Redis的分布式延迟队列)讲述了基于Java DelayQueue和Redis实现了分布式延迟队列,这种方案实现比较简单,应用于延迟小,消息量不大的场景是没问题的,毕竟Java DelayQueue是占用内存的。针对现用方案的不足,因而利用Redis的Sorted Set数据结构简单实现分布式延迟队列。html

Sorted Set

  • Redis 有序集合和集合同样也是string类型元素的集合,且不容许重复的成员。
  • 不一样的是每一个元素都会关联一个double类型的分数。redis正是经过分数来为集合中的成员进行从小到大的排序。
  • 有序集合的成员是惟一的,但分数(score)却能够重复。

设计思路

  1. 使用Redis的Sorted Set做为中转队列,为防止延迟消息量过大,维护多个Sorted Set,将延迟消息按照hash值平均分布到不一样的Sorted Set中。
  2. 因为Sorted Set自己具有有序性,将延迟时间做为score值和延迟消息绑定到一块儿存入Sorted Set中。
  3. 另起Java定时任务,每隔必定时间扫描全部Sorted Set,并经过ZRANGEBYSCORE操做取出符合条件的延迟消息,而后放入目标队列等待消费者消费。

代码实现

延迟队列建立

根据queueName分别建立中转队列(Sorted Set)和 目标队列key值,其中queueSize是中转队列的大小。redis

延迟消息投递

根据延迟消息的hash值,平均分配到不一样的中转队列(Sorted Set)中去。数据结构

中转定时任务

 

经过分布式锁来锁定惟一的线程来执行延迟消息迁移到目标队列的操做。遍历所有的中转队列,由于延迟消息是和延迟时间戳关联的,使用ZRANGEBYSCORE命令,取出延迟时间小于当前时间的50条消息并经过LPUSH命令放入目标队列里。分布式

延迟消息消费

 经过RPOP命令不断的从目标队列获取延迟消息,执行相应的消费逻辑。线程

总结

本文描述的实现方案还有诸多异常状况还没有考虑,好比生产者发送失败、消费者消费失败的状况,没法保证极端状况下生产者和消费者两端的数据一致性。该方案能够知足业务量不是很大、延迟时间较长、容许部分数据可能丢失的场景,好比用户签到提醒,能够根据用户签到的时间,次日在相应的时间点推送消息提醒用户继续签到。设计

相关文章
相关标签/搜索