【Redis】发布订阅与消息队列Day8(2026年)

写在前面

消息队列是分布式系统中不可或缺的组件,Redis除了作为缓存数据库,还提供了发布订阅(Pub/Sub)和Stream两种消息机制。虽然Redis不是专业的消息队列,但在轻量级场景下,它是一个不错的选择。今天我们来深入理解Redis的消息能力。

文章目录


一、Redis发布订阅(Pub/Sub)

1.1 什么是发布订阅?

实际场景:即时通讯系统中,用户上线后需要订阅多个群组消息,当有人在群组发言时,所有在线成员都能实时收到消息。

发布订阅(Pub/Sub)是一种消息通信模式:

  • 发布者(Publisher):发送消息到频道

  • 订阅者(Subscriber):订阅频道接收消息

  • 频道(Channel):消息传递的通道

    ┌────────────┐
    │ Publisher │──────┐
    └────────────┘ │

    ┌──────────────┐
    │ Channel │
    └──────────────┘

    ┌───────────┼───────────┐
    ▼ ▼ ▼
    ┌────────────┐ ┌────────────┐ ┌────────────┐
    │ Subscriber │ │ Subscriber │ │ Subscriber │
    └────────────┘ └────────────┘ └────────────┘

1.2 Pub/Sub基本命令

命令 说明
PUBLISH channel message 发布消息
SUBSCRIBE channel [channel...] 订阅频道
UNSUBSCRIBE [channel...] 取消订阅
PSUBSCRIBE pattern 模式订阅
PUNSUBSCRIBE [pattern...] 取消模式订阅
PUBSUB CHANNELS 查看活跃频道
PUBSUB NUMSUB channel 查看频道订阅数

1.3 Pub/Sub使用示例

订阅消息:

redis 复制代码
# 客户端1:订阅频道
SUBSCRIBE news:sports
# 返回:
# 1) "subscribe"
# 2) "news:sports"
# 3) (integer) 1

# 进入阻塞状态,等待消息

发布消息:

redis 复制代码
# 客户端2:发布消息
PUBLISH news:sports "NBA总决赛:湖人vs凯尔特人"
# 返回:(integer) 1  表示有1个订阅者收到消息

订阅者收到消息:

redis 复制代码
# 客户端1收到:
# 1) "message"
# 2) "news:sports"
# 3) "NBA总决赛:湖人vs凯尔特人"

1.4 模式订阅

使用通配符订阅多个频道:

redis 复制代码
# 订阅所有news开头的频道
PSUBSCRIBE news:*

# 可以匹配:
# news:sports, news:tech, news:weather 等

二、发布订阅的局限性

踩坑提醒:Redis Pub/Sub是实时的,如果订阅者离线,消息会丢失!

2.1 主要局限性

局限性 说明
消息不持久化 订阅者离线时收不到消息
无确认机制 发布后无法确认是否被消费
无消费组 不支持消费者组负载均衡
无消息回溯 无法重新消费历史消息
阻塞模式 订阅时客户端处于阻塞状态

2.2 适用场景

适用场景 不适用场景
实时消息推送 需要消息持久化
即时通讯 需要消息确认
简单事件通知 需要消费组
在线状态同步 高可靠性要求

三、Redis Stream数据结构

3.1 什么是Stream?

经验之谈:Redis 5.0引入的Stream是专门为消息队列设计的数据结构,解决了Pub/Sub的主要痛点。

Stream是Redis 5.0引入的数据结构,具有以下特点:

  • 消息持久化存储
  • 支持消费组
  • 支持消息确认(ACK)
  • 支持消息回溯
  • 类似Kafka的设计理念

3.2 Stream基本命令

命令 说明
XADD 添加消息
XREAD 读取消息
XRANGE 范围读取
XGROUP 创建消费组
XREADGROUP 消费组读取
XACK 确认消息
XDEL 删除消息
XLEN 消息长度
XINFO 查看Stream信息

3.3 Stream使用示例

添加消息:

redis 复制代码
# 添加消息到Stream
XADD mystream * name "zhangsan" age 25
# 返回:1640000000000-0(消息ID)

# * 表示由Redis自动生成ID
# 格式:毫秒时间戳-序列号

读取消息:

redis 复制代码
# 从头开始读取
XRANGE mystream - +
# 返回所有消息

# 读取最新消息(非阻塞)
XREAD COUNT 2 STREAMS mystream 0

# 阻塞读取最新消息
XREAD BLOCK 5000 STREAMS mystream $
# $表示最新消息位置,BLOCK 5000表示阻塞5秒

范围查询:

redis 复制代码
# 按时间范围查询
XRANGE mystream 1640000000000 1640000001000

# 只取2条
XRANGE mystream - + COUNT 2

四、Stream消费组

4.1 消费组概念

消费组(Consumer Group)是Stream的核心特性:

  • 多个消费者组成一个组

  • 每条消息只能被组内一个消费者消费

  • 支持消息确认和重新消费

    复制代码
                      ┌──────────────┐
                      │    Stream    │
                      └──────────────┘
                             │
                ┌────────────┼────────────┐
                ▼            ▼            ▼
         ┌──────────┐ ┌──────────┐ ┌──────────┐
         │Consumer-1│ │Consumer-2│ │Consumer-3│
         └──────────┘ └──────────┘ └──────────┘
                │            │            │
                └────────────┼────────────┘
                             │
                      ┌──────────────┐
                      │ Consumer Group│
                      └──────────────┘

4.2 消费组操作

创建消费组:

redis 复制代码
# 从头开始消费
XGROUP CREATE mystream mygroup 0

# 只消费新消息
XGROUP CREATE mystream mygroup $

# 创建成功后查看信息
XINFO GROUPS mystream

消费组读取消息:

redis 复制代码
# 消费组读取
XREADGROUP GROUP mygroup consumer1 COUNT 1 STREAMS mystream >

# > 表示读取未消费的消息
# consumer1是消费者名称

确认消息:

redis 复制代码
# 处理完消息后确认
XACK mystream mygroup 1640000000000-0
# 返回:(integer) 1

查看待处理消息:

redis 复制代码
# 查看待处理消息
XPENDING mystream mygroup

# 查看详细信息
XPENDING mystream mygroup - + 10

转移消息所有权:

redis 复制代码
# 将消息转移给其他消费者
XCLAIM mystream mygroup consumer2 0 1640000000000-0

4.3 消费组配置

redis 复制代码
# 设置最大长度,防止Stream无限增长
XADD mystream MAXLEN 1000 * field value

# 精确限制长度(性能更好)
XADD mystream MAXLEN ~ 1000 * field value

五、Stream vs Kafka对比

对比项 Redis Stream Kafka
消息持久化 支持(内存+磁盘) 支持(磁盘)
消息容量 有限(内存限制) 大(磁盘存储)
吞吐量 高(10万级/秒) 极高(百万级/秒)
消费组 支持 支持
消息确认 支持 支持
消息回溯 支持 支持
分区 单分区 多分区
运维复杂度
适用场景 轻量级消息队列 大数据流处理

六、踩坑提醒

踩坑提醒:消息丢失问题

问题1:Pub/Sub消息丢失

redis 复制代码
# 订阅者离线时,消息直接丢失
SUBSCRIBE channel
# 离线期间发布的消息无法收到

解决方案:

  • 使用Stream替代Pub/Sub
  • 使用专业消息队列(RabbitMQ、Kafka)

问题2:Stream消息堆积

redis 复制代码
# Stream无限增长会耗尽内存
XADD stream * data value
# 持续添加不删除

解决方案:

redis 复制代码
# 使用MAXLEN限制长度
XADD stream MAXLEN ~ 10000 * data value

# 定期清理
XTRIM stream MAXLEN 10000

问题3:消费者宕机消息未确认

redis 复制代码
# 消费者读取消息后宕机,消息处于pending状态
XREADGROUP GROUP mygroup consumer1 STREAMS stream >
# 宕机...

解决方案:

redis 复制代码
# 其他消费者接管pending消息
XCLAIM stream mygroup consumer2 60000 pending-message-id
# 60000是消息空闲时间(毫秒)

七、实际应用案例

7.1 实时消息推送

redis 复制代码
# 发布者
XADD notifications * user_id 1001 content "您有新消息"

# 消费者
XREADGROUP GROUP notify_group consumer1 BLOCK 5000 STREAMS notifications >

7.2 日志收集

redis 复制代码
# 应用服务写入日志
XADD app:logs * level ERROR service user-api message "连接超时"

# 日志处理服务消费
XREADGROUP GROUP log_group log_processor STREAMS app:logs >

7.3 事件溯源

redis 复制代码
# 记录领域事件
XADD order:events * event OrderCreated order_id 1001 amount 99.9
XADD order:events * event OrderPaid order_id 1001 paid_at 1640000000
XADD order:events * event OrderShipped order_id 1001 shipped_at 1640000100

# 回放事件
XRANGE order:events - +

八、面试高频考点

考点1:Redis做消息队列的优缺点?

答案:

优点 缺点
部署简单,无需额外组件 内存限制,不适合海量数据
低延迟,高性能 不支持复杂路由
支持消费组和消息确认 功能不如专业MQ丰富
支持消息持久化(Stream) 没有死信队列机制

考点2:Pub/Sub和Stream的区别?

答案:

对比项 Pub/Sub Stream
消息持久化 不支持 支持
离线消息 不支持 支持
消费组 不支持 支持
消息确认 不支持 支持
消息回溯 不支持 支持
适用场景 实时推送 可靠消息队列

考点3:如何保证消息不丢失?

答案:

  1. 使用Stream替代Pub/Sub
  2. 开启AOF持久化(appendfsync everysec)
  3. 使用消费组确认机制(XACK)
  4. 监控pending消息,及时处理未确认消息
  5. 设置合理的消息重试机制

考点4:Stream的消息ID有什么特点?

答案:

  • 格式:毫秒时间戳-序列号,如1640000000000-0
  • 时间戳由Redis服务器生成,保证递增
  • 同一毫秒内通过序列号区分
  • 支持自定义ID,但通常使用*让Redis自动生成

九、参考资料

  1. Redis官方文档 - Pub/Sub
  2. Redis官方文档 - Streams

十、互动话题

  1. 你在项目中使用Redis作为消息队列遇到过什么问题?
  2. Stream和Kafka你会如何选择?各自的适用场景是什么?
  3. 如何设计一个基于Stream的可靠消息队列系统?

欢迎在评论区分享你的经验和见解!


下一期预告:Day9 - Redis主从复制,敬请期待!

相关推荐
道友可好1 小时前
OpenSpec:轻到起飞的 AI 编程规范层
前端·人工智能·后端
sukioe1 小时前
Redis 持久化+高可用详解:RDB/AOF/混合/主从/哨兵/集群
数据库·redis·缓存
IT_陈寒1 小时前
React状态管理这个坑,我爬了整整三天才出来
前端·人工智能·后端
全栈软件开发1 小时前
祈福导航系统V1.1更新 优化后端控制逻辑和前台UI
数据库·祈福导航系统
用户8356290780511 小时前
如何使用 Python 在 PowerPoint 演示文稿中添加漏斗图
后端
ServBay1 小时前
Qwen3.7-Max 发布,全能智能体基座
后端·aigc·ai编程
189228048612 小时前
NV023固态MT29F16T08GWLCEJ9-QBES:C
大数据·服务器·人工智能·科技·缓存
KeepPush2 小时前
Python JSON 完全指南:从基础到实战,掌握数据交换核心技能
后端
Cosolar2 小时前
深度测评 | QoderWork:当 AI 不再只是"聊天搭子",而是真能帮你干活的桌面智能体
人工智能·后端·程序员