用Redis实现延时任务

解决的问题

订单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宕机了,根据持久化机制,也只可能丢失一点消息,影响不大

  • 消息不存在重复消费的问题

每个客户端都是从同一个目标队列中获取任务的,不存在重复消费的问题

你可能感兴趣的:(redis,数据库,缓存)