解决的问题
订单7天未处理,系统自动确认收货
红包24小时未被查收,自动退款
Redis方案
- Redis过期事件监听
- Redisson内置的延时队列
Redis过期事件监听
Redis中的默认channel _keyevent@0_:expired负责监听key的过期事件。我们只需要监听这个channel,就可以拿到过期的key的消息,进而实现延时任务的功能。
存在的问题
- 时效性差
【惰性删除+定期删除,会存在到了过期时间key还未被删除,进而没有发布过期事件的情况】
- 丢消息
【redis的pub/sub模式中的消息并不支持持久化,发送者将消息发送到指定频道,订阅者监听相应的频道以接收消息,当没有订阅者时,消息会被直接丢弃】
- 多服务实例下存在消息重复消费的问题
【只有广播模式,生产者向特定频道发布一条消息时,所有订阅相关频道的消费者都能够收到该消息】
Redisson内置的延时队列
Redisson是开源的java语言redis客户端,提供了很多开箱即用的功能。
实现延时队列的原理
redisson的延迟队列RDelayQueue是基于Redis的SortedSet来实现的。Redisson将需要执行的延时任务插入到SortedSet中,并给他们设置一定的过期时间作为分数。Redisson使用zrangebyscore命令扫描SortedSet中过期的元素,然后将这些元素从SortedSet中移除,将其加入到就绪消息队列中。就绪消息队列是一个阻塞队列,有消息进入就会被监听到。这样可以避免对整个SortedSet进行轮训,提高了执行效率。
相对于Redis过期事件监听,具备以下优势:
- 减少了消息丢失的可能
DelayQueue中的消息会被持久化,即使Redis宕机了,根据持久化机制,也只可能丢失一点消息,影响不大
- 消息不存在重复消费的问题
每个客户端都是从同一个目标队列中获取任务的,不存在重复消费的问题