Java 源码剖析(21)--Redis 如何实现消息队列

本文详细介绍了 Redis 中实现消息队列的四种方法,包括使用 List、ZSet、发布订阅模式以及 Stream。着重讨论了 List 和 Stream 在 Java 中的实现,强调了 Stream 提供的消费者确认机制,提高了消息的可靠性和系统稳定性。
摘要由CSDN通过智能技术生成

1)实现消息队列的方式

在 Redis 中实现消息队列的方式有几种?
早在 Redis 2.0 版本之前使用 Redis 实现消息队列的方式有两种:

  • 使用 List 类型实现
  • 使用 ZSet 类型实现

其中使用List 类型实现的方式最为简单和直接,它主要是通过 lpush、rpop 存入和读取实现消息队列的,如下图所示:
在这里插入图片描述
lpush 可以把最新的消息存储到消息队列(List 集合)的首部,而 rpop 可以读取消息队列的尾部,这样就实现了先进先出,如下图所示:
在这里插入图片描述
命令行的实现命令如下:

127.0.0.1:6379> lpush mq "java" #推送消息 java
(integer) 1
127.0.0.1:6379> lpush mq "msg" #推送消息 msg
(integer) 2
127.0.0.1:6379> rpop mq #接收到消息 java
"java"
127.0.0.1:6379> rpop mq #接收到消息 msg
"mq"

其中,mq 相当于消息队列的名称,而 lpush 用于生产并添加消息,而 rpop 用于拉取并消费消息。
使用 List 实现消息队列的优点是消息可以被持久化,List 可以借助 Redis 本身的持久化功能,AOF 或者是 RDB 或混合持久化的方式,用于把数据保存至磁盘,这样当 Redis 重启之后,消息不会丢失。

但使用 List 同样存在一定的问题,比如消息不支持重复消费、没有按照主题订阅的功能、不支持消费消息确认等。

ZSet 实现消息队列的方式和 List 类似,它是利用 zadd 和 zrangebyscore 来实现存入和读取消息的,这里就不重复叙述了。但 ZSet 的实现方式更为复杂一些,因为 ZSet 多了一个分值(score)属性,我们可以使用它来实现更多的功能,比如用它来存储时间戳,以此来实现延迟消息队列等。

ZSet 同样具备持久化的功能,List 存在的问题它也同样存在,不但如此,使用 ZSet 还不能存储相同元素的值。因为它是有序集合,有序集合的存储元素值是不能重复的,但分值可以重复,也就是说当消息值重复时,只能存储一条信息在 ZSet 中。

在 Redis 2.0 之后 Redis 就新增了专门的发布和订阅的类型,Publisher(发布者)和 Subscriber(订阅者)来实现消息队列了,它们对应的执行命令如下:

  • 发布消息,publish channel “message”;
  • 订阅消息,subscribe channel

使用发布和订阅的类型,我们可以实现主题订阅的功能,也就是 Pattern Subscribe 的功能。因此我们可以使用一个消费者“queue_*”来订阅所有以“queue_”开头的消息队列,如下图所示:
在这里插入图片描述
发布订阅模式的优点很明显,但同样存在以下 3 个问题:

  • 无法持久化保存消息,如果 Redis 服务器宕机或重启,那么所有的消息将会丢失;
  • 发布订阅模式是“发后既忘”的工作模式,如果有订阅者离线重连之后就不能消费之前的历史消息;
  • 不支持消费者确认机制,稳定性不能得到保证,例如当消费者获取到消息之后,还没来得及执行就宕机了。因为没有消费者确认机制,Redis 就会误以为消费者已经执行了,因此就不会重复发送未被正常消费的消息了,这样整体的 Redis 稳定性就被没有办法得到保障了。

然而在 Redis 5.0 之后新增了 Stream 类型,我们就可以使用 Stream 的 xadd 和 xrange 来实现消息的存入和读取了,并且 Stream 提供了 xack 手动确认消息消费的命令,用它我们就可以实现消费者确认的功能了,使用命令如下:

127.0.0.1:6379> xack mq group1 1580959593553-0
(integer) 1

相关语法如下:

xack key group-key ID [ID ...] 

消费确认增加了消息的可靠性,一般在业务处理完成之后,需要执行 ack 确认消息已经被消费完成,整个流程的执行如下图所示:
在这里插入图片描述
其中“Group”为群组,消费者也就是接收者需要订阅到群组才能正常获取到消息。
以上就 Redis 实现消息队列的四种方式,他们分别是:

  • 使用 List 实现消息队列;
  • 使用 ZSet 实现消息队列;
  • 使用发布订阅者模式实现消息队列;
  • 使用 Stream 实现消息队列。

2)使用 List 实现消息队列

在 Java 程序中我们需要使用 Redis 客户端框架来辅助程序操作 Redis,比如 Jedis 框架。
使用 Jedis 框架首先需要在 pom.xml 文件中添加 Jedis 依赖,配置如下:

<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
  <groupId>redis.clients</groupId>
  <artifactId>jedis</artifactId>
  <version>${version}</version>
</dependency>

List 实现消息队列的完整代码如下:

import redis.clients.jedis.Jedis;
publicclass ListMQTest {
   
    public static void main(String[] args){
   
        // 启动一个线程作为消费者
        new Thread(() -> consumer()).start();
        // 生产者
        producer();
    }
    /**
     * 生产者
     */
    public static void producer() {
   
        Jedis jedis = new Jedis("127.0.0.1", 6379
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值