基于Redis实现延时任务

两种方案:

  1. Redis 过期事件监听
  2. Redisson 内置的延时队列

Redis 过期事件监听这种方案存在很多问题,建议使用 Redisson 内置的 DelayedQueue 方案。

Redis 过期事件监听实现延时任务原理

Redis 2.0 引入了发布订阅 (pub/sub) 功能。

在 pub/sub 模式下,生产者需要指定消息发送到哪个 channel 中,而消费者则订阅对应的 channel 以获取消息。

Redis 中有很多默认的 channel,这些 channel 是由 Redis 本身向它们发送消息的,而不是我们自己编写的代码。其中,__keyevent@0__:expired 就是一个默认的 channel,负责监听 key 的过期事件。也就是说,当一个 key 过期之后,Redis 会发布一个 key 过期的事件到__keyevent@<db>__:expired这个 channel 中。

我们只需要监听这个 channel,就可以拿到过期的 key 的消息,进而实现了延时任务功能。

这个功能被 Redis 官方称为 keyspace notifications ,作用是实时监控实时监控 Redis 键和值的变化。

Redis过期时间监听的缺陷

1.时效性差

过期事件消息在 Redis 服务器删除 key 时发布,而不是在 key 过期之后直接发布。

常用过期数据删除策略:

  1. 惰性删除:只会在取出 key 的时候才对数据进行过期检查。这样对 CPU 最友好,但是可能造成太多过期 key 没有被删除。
  2. 定期删除:每隔一段时间抽取一批 key 执行删除过期 key 操作。并且,Redis 底层会通过限制删除操作执行的时长和频率来减少删除操作对 CPU 时间的影响。

定期删除对内存更加友好,惰性删除对 CPU 更加友好,所以 Redis 采用的是 定期删除+惰性/懒汉式删除

因此,会存在设置了 key 的过期时间,但到了指定时间 key 还未被删除,进而没有发布过期事件的情况。

2.丢消息

与消息队列不同,Redis 的 pub/sub 模式中的消息并不支持持久化。在 Redis 的 pub/sub 模式中,发布者将消息发送给指定的频道,订阅者监听相应的频道以接收消息。当没有订阅者时,消息会被直接丢弃,在 Redis 中不会存储该消息。

3.多服务实例下重复消费

Redis 的 pub/sub 模式目前只有广播模式,这意味着当生产者向特定频道发布一条消息时,所有订阅相关频道的消费者都能够收到该消息。

这个时候,我们需要注意多个服务实例重复处理消息的问题,这会增加代码开发量和维护难度。

Redisson延迟队列原理和优势

Redisson 是开源的 Java 语言 Redis 客户端,提供很多开箱即用的功能,比如多种分布式锁的实现、延时队列。可借助 Redisson 内置的延迟队列 RDelayedQueue 实现延时任务。

SortedSet 是有序集合,其中的每个元素可设置分数,代表该元素的权重。Redisson 利用这一特性,将需要延迟执行的任务插入到 SortedSet 中,并设置过期时间作为分数。

Redisson 使用 zrangebyscore 命令扫描 SortedSet 中过期的元素,然后将这些过期元素从 SortedSet 中移除,并将它们加入到就绪消息列表中。

就绪消息列表是一个阻塞队列,有消息进入就会被监听到。避免对整个 SortedSet 进行轮询,提高执行效率。

优势:

  1. 减少丢消息的可能:DelayedQueue 中的消息会被持久化,即使 Redis 宕机了,也只可能丢失一点消息,影响不大。
  2. 消息不存在重复消费问题:每个客户端都是从同一个目标队列中获取任务的,不存在重复消费的问题。

跟 Redisson 内置的延时队列相比,消息队列可以通过保障消息消费的可靠性、控制消息生产者和消费者的数量等手段来实现更高的吞吐量和更强的可靠性,实际项目中首选消息队列的延时消息这种方案。

相关推荐
q***420526 分钟前
PHP使用Redis实战实录2:Redis扩展方法和PHP连接Redis的多种方案
开发语言·redis·php
苦瓜炒蛋挞27 分钟前
小迪安全第二十二天-安全开发-PHP应用&数据库操作&留言板功能&第三方插件
数据库·网络安全·php·小迪安全
天选之女wow32 分钟前
【Hard——Day8】65.有效数字、68.文本左右对齐、76.最小覆盖子串
linux·运维·redis·算法·leetcode
chushiyunen39 分钟前
redis命令 geo(对地理坐标的支持)
数据库·redis·缓存
baivfhpwxf20231 小时前
删除数据表SQL,不是删除数据,是删除表结构
数据库·sql
码界奇点1 小时前
深入解析MySQL6存储过程游标与触发器的实战应用与性能优化
数据库·sql·性能优化·七牛云存储
鸽鸽程序猿2 小时前
【Redis】List类型介绍
数据库·redis·list
帅中的小灰灰2 小时前
C++编程观察者设计模式
数据库·c++·设计模式
2501_941664962 小时前
云计算与边缘计算:新时代数字化转型的双轮驱动
数据库
x***58702 小时前
GitHub星标10万+的Redis项目,使用教程
数据库·redis·github