用Redis实现延迟队列,耗时几天研究了两种方案,发现并不简单

本文介绍了使用Redis实现延迟队列的两种方案,包括基于监听过期key的实现,通过Redis发布订阅模式和keyspace notifications监听。然而,监听过期key存在消息延迟和丢失等问题。相比之下,Redisson提供的延迟队列解决方案更稳定,通过lua脚本确保任务及时执行,减少丢消息的风险,并避免广播消费问题。
摘要由CSDN通过智能技术生成

背景

前段时间有个小项目需要使用延迟任务,谈到延迟任务,我脑子第一时间一闪而过的就是使用消息队列来做,比如RabbitMQ的死信队列又或者RocketMQ的延迟队列,但是奈何这是一个小项目,并没有引入MQ,我也不太想因为一个延迟任务就引入MQ,增加系统复杂度,所以这个方案直接就被pass了。

虽然基于MQ这个方式走不通了,但是这个项目中使用到Redis,所以我就想是否能够使用Redis来代替MQ实现延迟队列的功能,于是我就查了一下有没有现成可用的方案,别说,还真给我查到了两种方案,并且我还仔细研究对比了这两个方案,发现要想很好的实现延迟队列,并不简单。

监听过期key

基于监听过期key的方式来实现延迟队列是我查到的第一个方案,为了弄懂这个方案实现的细节,我还特地去扒了扒官网,还真有所收获

1、Redis发布订阅模式

一谈到发布订阅模式,其实一想到的就是MQ,只不过Redis也实现了一套,并且跟MQ贼像,如图:
在这里插入图片描述图中的channel的概念跟MQ中的topic的概念差不多,你可以把channel理解成MQ中的topic。

生产者在消息发送时需要到指定发送到哪个channel上,消费者订阅这个channel就能获取到消息。

2、keyspace notifications

在Redis中,有很多默认的channel,只不过向这些channel发送消息的生产者不是我们写的代码,而是Redis本身。当消费者监听这些channel时,就可以感知到Redis中数据的变化。

这个功能Redis官方称为keyspace notifications,字面意思就是键空间通知。

这些默认的channel被分为两类:

  • 以__keyspace@:为前缀,后面跟的是key的名称,表示监听跟这个key有关的事件。举个例子,现在有个消费者监听了__keyspace@0:sanyou这个channel,sanyou就是Redis中的一个普通key,那么当sanyou这个key被删除或者发生了其它事件,那么消费者就会收到sanyou这个key删除或者其它事件的消息
  • 以__keyevent@:为前缀,后面跟的是消息事件类型,表示监听某个事件同样举个例子,现在有个消费者监听了__keyevent@0:expired这个channel,代表了监听key的过期事件。那么当某个Redis的key过期了(expired),那么消费者就能收到这个key过期的消息。如果把expired换成del,那么监听的就是删除事件。具体支持哪些事件,可从官网查。

上述db是指具体的数据库,Redis不是默认分为16个库么,序号从0-15,所以db就是0到15的数字,示例中的0就是指0对应的数据库。
在这里插入图片描述

3、延迟队列实现原理

通过对上面的两个概念了解之后,应该就对监听过期key的实现原理一目了然了,其实就是当这个key过期之后,Redis会发布一个key过期的事件到__keyevent@__:expired这个channel,只要我们的服务监听这个channel,那么就能知道过期的Key,从而就算实现了延迟队列功能。

所以这种方式实现延迟队列就只需要两步:

  • 发送延迟任务,key是延迟消息本身,过期时间就是延迟时间
  • 监听__keyevent@__:expired这个channel,处理延迟任务
4、demo

好了,基本概念和核心原理都说完了之后,又到了show me the code环节。

好巧不巧,Spring已经实现了监听__keyevent@__:expired这个channel这个功能,__keyevent@__:expired中的*代表通配符的意思,监听所有的数据库。

所以demo写起来就很简单了,只需3步即可

引入pom

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <version>2.2.5.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.2.5.RELEASE</version>
</dependency>

配置类

@Configuration
public 
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值