我们将以“在线购物网站”作为例子贯穿全文,帮助大家理解Redis Pub/Sub在不同场景下的应用。
1. 什么是 Redis 的 Pub/Sub 机制
专业性描述
Redis Pub/Sub(发布/订阅)是一种消息通信模式,发送者(发布者)将消息发送到指定的频道,订阅了该频道的接收者(订阅者)都会收到此消息。这种模式实现了发布者和订阅者之间的解耦,发布者不需要知道订阅者的存在,订阅者也不需要知道发布者的存在。
大白话类比
这就像电台广播。电台(发布者)在某个频率(频道)上广播节目,所有调到这个频率的收音机(订阅者)都能收到节目。电台不知道有多少收音机在收听,收音机也不知道电台在哪里,它们只通过频率这个中介联系起来。
“在线购物网站”示例
假设我们有一个在线购物网站,当有新订单生成时,需要同时做以下几件事:
- 发送短信通知用户
- 更新商品库存
- 记录订单日志
- 更新用户积分
使用Redis Pub/Sub,我们可以让订单服务发布一个消息到 order.created 频道,其他服务订阅这个频道,各自处理自己的业务逻辑。
2. 应用场景:消息发布/订阅,模式订阅
2.1 基本发布/订阅
“在线购物网站”示例
订单服务发布订单创建消息:
# 订单服务发布消息
PUBLISH order.created “订单ID: 1001, 用户ID: 2001, 金额: 299.00”
短信服务订阅该频道:
# 短信服务订阅频道
SUBSCRIBE order.created
# 收到消息后,发送短信给用户
库存服务订阅该频道:
# 库存服务订阅频道
SUBSCRIBE order.created
# 收到消息后,减少库存
2.2 模式订阅
专业性描述
模式订阅允许订阅者通过通配符一次订阅多个频道。Redis支持两种通配符:* 匹配任意多个字符,? 匹配一个字符。
“在线购物网站”示例
假设我们有多个订单相关的事件:
order.created 订单创建
order.paid 订单支付
order.shipped 订单发货
order.completed 订单完成
日志服务希望订阅所有订单相关的事件:
# 使用模式订阅
PSUBSCRIBE order.*
# 这样会收到所有以“order.”开头的事件
3. Pub/Sub 的优点、缺点、适用场景
3.1 优点
- 解耦:发布者和订阅者不需要知道对方的存在,只需要关注频道。
- 实时性:消息发布后立即推送给所有订阅者。
- 扩展性:可以方便地增加新的订阅者,不影响现有系统。
- 简单易用:Redis命令简单,无需额外组件。
“在线购物网站”示例
当我们需要增加一个新的功能:订单成功后给用户发放优惠券。只需要新增一个优惠券服务,订阅 order.completed 频道即可,不需要修改订单服务。这种基于事件的通信方式非常适合构建松耦合的分布式系统。
3.2 缺点
- 消息不可持久化:Redis Pub/Sub的消息是即时的,如果没有订阅者,消息就丢失了。订阅者掉线期间的消息也会丢失。
- 无消息堆积能力:如果订阅者处理速度慢,消息不会被缓存,会导致消息丢失。
- 无消息确认机制:发布者不知道消息是否被成功接收和处理。
- 不支持消息重试:如果处理失败,无法重新获取消息。
“在线购物网站”示例
假设短信服务在订单创建时宕机了,那么订单创建的消息就会丢失,用户收不到短信通知。而且即使短信服务恢复,也不会收到之前的消息。这对于关键业务来说是致命缺陷。
3.3 适用场景
- 实时通知:如在线聊天、实时弹幕。
- 事件广播:如配置更新、服务发现。
- 轻量级消息队列:对消息可靠性要求不高,允许少量丢失的场景。
- 解耦系统组件:组件间需要解耦,但不要求强可靠性的场景。
“在线购物网站”示例
适合使用Redis Pub/Sub的场景:
- 用户登录/登出状态广播(用于在线用户列表)
- 商品价格变化通知(前台展示实时更新)
- 管理员操作广播(多个后台需要同步状态)
不适合使用Redis Pub/Sub的场景:
- 订单支付结果通知(不能丢失)
- 库存扣减消息(必须保证处理)
- 积分变更记录(需要可靠传递)
4. List、Redis Pub/Sub、Redis Stream、专业级消息中间件的对比
下面我们通过“在线购物网站”的不同场景,对比这四种消息传递方式。
4.1 Redis List(列表)
专业性描述
Redis List是一个简单的列表数据结构,可以用作消息队列。生产者通过LPUSH添加消息,消费者通过RPOP或BRPOP获取消息。
“在线购物网站”示例
商品搜索服务将用户搜索关键词放入队列,异步分析搜索热点:
# 搜索服务生产消息
LPUSH search:keywords “iphone 15”
LPUSH search:keywords “华为mate60”
# 分析服务消费消息
BRPOP search:keywords 0
特点:
- 消息可持久化
- 支持多个消费者,但每条消息只能被一个消费者获取
- 简单,但功能有限
- 无消息确认机制
4.2 Redis Pub/Sub(发布/订阅)
“在线购物网站”示例
用户下单后,需要同时通知多个服务:
# 订单服务发布
PUBLISH order.paid “订单ID: 1001, 金额: 299.00”
# 多个服务订阅
# 短信服务、库存服务、积分服务等
特点:
- 一对多广播
- 实时推送
- 消息不持久化
- 无消息堆积能力
4.3 Redis Stream(流)
专业性描述
Redis 5.0引入的数据类型,专门为消息队列设计。支持消息持久化、消费者组、消息确认等特性。
“在线购物网站”示例
订单支付成功后的可靠消息传递:
# 支付服务生产消息
XADD order:payments * orderId 1001 userId 2001 amount 299.00
# 创建消费者组
XGROUP CREATE order:payments sms-group $ MKSTREAM
XGROUP CREATE order:payments stock-group $ MKSTREAM
# 不同消费者组独立消费
# 短信服务消费者组
XREADGROUP GROUP sms-group consumer1 COUNT 1 STREAMS order:payments >
# 库存服务消费者组
XREADGROUP GROUP stock-group consumer1 COUNT 1 STREAMS order:payments >
特点:
- 消息可持久化
- 支持消费者组,同一消息可被不同组消费
- 支持消息确认和重试
- 功能丰富,接近专业消息队列
4.4 专业级消息中间件(如RabbitMQ、Kafka)
“在线购物网站”示例
大规模订单处理,需要高可靠性和高吞吐量:
- Kafka:用于用户行为日志收集,海量日志数据
- RabbitMQ:用于订单状态同步,需要复杂路由
特点:
- 功能最完整
- 支持各种消息模式
- 高可靠性、高可用性
- 管理和运维复杂
- 资源消耗较大
4.5 对比表格
| 特性 |
Redis List |
Redis Pub/Sub |
Redis Stream |
专业消息中间件 |
| 消息持久化 |
支持 |
不支持 |
支持 |
支持 |
| 消息广播 |
不支持 |
支持 |
支持消费者组 |
支持 |
| 消息确认 |
不支持 |
不支持 |
支持 |
支持 |
| 消息重试 |
不支持 |
不支持 |
支持 |
支持 |
| 消息顺序 |
先进先出 |
无保证 |
有序 |
有序 |
| 吞吐量 |
中 |
高 |
中高 |
高 |
| 可靠性 |
低 |
低 |
中 |
高 |
| 复杂度 |
简单 |
简单 |
中等 |
复杂 |
| 适用场景 |
简单任务队列 |
实时通知广播 |
可靠消息队列 |
企业级应用 |
“在线购物网站”选择建议:
- 实时在线人数统计:使用 Pub/Sub(实时性要求高,允许丢失)
- 订单支付结果通知:使用 Stream(需要可靠性,但不想引入复杂中间件)
- 用户行为日志收集:使用 Kafka(海量数据,高吞吐)
- 异步发送邮件:使用 List(简单,允许少量丢失)
5. 记忆技巧与实战要点
核心口诀:
Pub/Sub是广播,实时推送不可少。
消息丢了不负责,适合通知和报警。
List能做简单队,一消费者消费掉。
Stream才是真队列,持久确认功能强。
专业中间件虽好,复杂场景再上场。
6. Redis Pub/Sub 应用架构图

图例解读
- 订单服务发布订单创建消息到
order.created 频道
- 短信、库存、积分、日志服务都订阅了这个频道,都会收到消息
- 用户服务发布用户注册消息到
user.registered 频道
- 日志和推送服务订阅了这个频道
- 商品服务发布价格更新消息到
price.updated 频道
- 日志和推送服务订阅了这个频道
通过这样的架构,各个服务之间完全解耦,新增服务只需要订阅感兴趣的频道,无需修改发布者代码。
7. 实战要点
选择依据:
需要广播且允许丢失:用Pub/Sub
简单队列,单消费者:用List
需要可靠性,多消费者:用Stream
企业级复杂需求:用专业消息中间件
注意事项:
- Pub/Sub订阅后,客户端会阻塞等待消息,需要单独连接
- Stream的消息不自动删除,需要定期清理
- List作为队列时,注意处理消费者崩溃的情况
- 专业消息中间件部署和维护成本较高
监控指标:
- Pub/Sub客户端数量
- Stream消息堆积数
- List队列长度
- 消息处理延迟
容灾设计:
- Pub/Sub:订阅者断线重连后无法收到之前消息,需有补偿机制
- Stream:配置合理的持久化策略
- 重要业务:需要有死信队列和重试机制
性能优化:
- 批量处理消息
- 合理设置消费者数量
- 监控内存使用,避免消息堆积
总结
Redis Pub/Sub是一种简单高效的发布/订阅机制,非常适合实时通知、事件广播等场景。但在需要消息可靠性、持久化的场景下,应该选择Redis Stream或专业消息中间件。在实际应用中,需要根据业务需求、可靠性要求、系统复杂度等因素综合考虑,选择合适的消息传递方式。对于希望深入探讨更多后端架构与中间件选型的朋友,欢迎访问云栈社区进行交流。