Redis(二):Redis消息队列

Published on 2025-06-30 11:17 in 分类: 博客 with 狂盗一枝梅
分类: 博客

使用Redis实现消息队列有两种方式:list队列模式以及发布订阅模式。

一、list队列模式

1、list队列的原理

在上一篇文章《Redis(一):Redis数据类型和常用命令》中已经详细讲解了Redis中list相关的操作。list底层是个双向链表,头部和尾部的操作效率非常高,其操作命令也符合队列API的行为方式。我们在使用list作为消息队列的时候,会使用lpush命令将消息放入队列,使用rpop命令将消息出队列。

image-20250627224658106

需要注意的是rpop命令是一次性命令,它在执行前并不知道消息队列中是否有消息,可以预料到的是,如果队列中一直没有消息,只能通过rpop命令一直轮询。为了解决这个问题,可以使用brpop命令:

brpop key [key ...] timeout

brpop命令中的timeout参数是必传的,当它为0的时候表示无限期阻塞等待;不为零的时候计时结束就会自动放弃阻塞等待。

brpop命令返回值有两个值,第一个值是key的名字,第二个值是弹出的元素值,如果从队列中取不出来数据,会一直阻塞,在一定范围内没有取出则返回null。需要注意brpop命令并不会阻塞主线程,brpop虽然是个阻塞命令,但是它会通过如下机制避免阻塞主线程:

  • 非忙等待:当 BRPOP 监听列表为空时,Redis 会将客户端连接标记为“阻塞状态”,并将其从活跃客户端列表中移除,主线程不会持续轮询或等待,而是继续处理其他请求

  • 事件驱动:Redis 使用事件循环(如 epoll)管理客户端连接。阻塞的客户端会被挂起,直到目标列表有新元素插入时,Redis 通过事件回调唤醒对应的客户端连接

2、list队列演示

第一步:进入容器

我在6.2.1版本的redis下做个演示。由于我使用了docker,所以需要先进入我的redis容器(容器名为redis):

docker exec -it redis /bin/bash

然后进入redis-cli命令所在的目录:

cd /usr/local/bin

运行redis-cli命令:

./redis-cli

进入redis交互命令行,执行auth命令做个认证:

auth 123456

依照此步骤打开三个会话页面:

image-20250627230511980

第二步:发送/接收消息

三个会话中,第一个会话用于向队列发送消息,第二个和第三个会话使用brpop命令接收消息。

动画45_resize

可以看到,brpop命令即使key不存在,也可以持续监听,并且当key被创建而且list中有值时会自动将值取出来。多个监听者可以同时监听同一个消息队列,但是同一个值只能被一个监听者获取到。

二、发布订阅模式

1、发布订阅模式简介

发布订阅模式和rabbitmq消息队列的topic模式很像,多个客户端订阅同一个channel,channel发布消息的时候,每个客户端都能收到相同的消息。

image-20250630102158818

消息订阅命令:subscribe channel [channel ...],也就是说该命令可以订阅多个channel。

image-20250630102728000

消息发送命令:publish channel message该命令只能向一个channel发送命令。

全部命令如下所示:

命令 描述
publish channel message 将信息发送到指定的频道。
subscribe channel [channel ...] 订阅给定的一个或多个频道的信息。
pubsub subcommand [argument [argument ...]] 查看订阅与发布系统状态。
PUBSUB CHANNELS:列出当前活跃的频道
PUBSUB NUMSUB [channel ...]:返回指定频道的订阅者数量
unsubscribe [channel [channel ...]] 指退订给定的频道。
目前还不知道如何在redis-cli中执行该命令,因为ctrl+c就已经实现退订了。
psubscribe pattern [pattern ...] 订阅一个或多个符合给定模式的频道。
punsubscribe [pattern [pattern ...]] 退订所有给定模式的频道。

2、发布订阅模式演示

接下来打开三个客户端,一个用于发布,另外两个用来订阅。

动画1_resize

3、发布订阅模式分析

发布订阅模式的优点:发布者和订阅者不需要知道彼此的存在,功能解耦。

发布订阅模式的缺点

  • 消息没有持久化,如果消费者不在线,消息会丢失
  • 没有ack机制,无法保证消息被成功消费。
  • 同样因为没有持久化,如果消费者断线重连,中间的消息会丢失。
  • Redis服务重启后消息会丢失。

综合来看,redis在消息队列方面功能并不完善,如果需要用到消息队列,最好使用专业的消息队列中间件,比如rabbitmq、kafka等。

当然,redis5中引入了Stream,Stream做了数据的持久化处理,一定方面弥补了发布订阅模式的缺点。。。建议还是不要用。


#redis
复制 复制成功