📚 实战篇 25. Redis 消息队列 - 认识 MQ 与方案对比 (学习文档)
一、 什么是消息队列 (MQ)?
消息队列(Message Queue) ,字面意思就是存放消息的队列。最简单的消息队列模型包含三个核心角色:
- 生产者 (Producer): 负责生成消息并发送到队列中(比如我们的 Tomcat 主线程,负责生成订单号)。
- 消息代理 (Broker): 负责接收并存储消息,确保消息的安全和有序(比如我们要用的 Redis)。
- 消费者 (Consumer): 负责从队列中获取消息并处理(比如我们的后台写库线程)。
引入 MQ 的三大核心优势(面试必背):
- 异步解耦: 生产者不用等消费者处理完,扔完消息就走,极大提高接口响应速度。
- 削峰填谷: 面对瞬间高并发流量(洪水),MQ 就像一个水库把水蓄起来,消费者再以自己能承受的速度慢慢平缓地“排水”(消费),保护了脆弱的 MySQL 数据库。
- 数据可靠性: 专业的 MQ 会把消息持久化到磁盘,即使消费者宕机重启,消息依然在队列里,不会丢失。
二、 Redis 实现 MQ 的三种方案大比拼
在黑马点评项目中,我们不需要引入像 RabbitMQ、Kafka 这样沉重的专业中间件,利用现成的 Redis 就能完美实现 MQ。Redis 历史上演进了三种不同的 MQ 实现方案:
方案 1:基于 List 数据结构
Redis 的 List 是一个双向链表,天然具备队列的“先进先出 (FIFO)”特性。
-
实现方式: 生产者利用
LPUSH从左侧插入消息,消费者利用BRPOP从右侧阻塞式拉取消息。 -
优点: 实现极度简单,没有任何学习成本,依靠 Redis 原生持久化(RDB/AOF)保证数据安全。
-
致命缺点: * 不支持发布订阅: 一条消息只能被一个消费者消费,无法广播给多个服务。
- 缺乏确认机制 (ACK): 消费者
BRPOP拿到消息后,这条消息就从 Redis 里消失了。如果消费者拿到消息还没来得及处理就宕机了,这条消息就永久丢失了!
- 缺乏确认机制 (ACK): 消费者
方案 2:基于 Pub/Sub (发布订阅)
这是 Redis 专门为消息路由设计的模式。
-
实现方式: 生产者使用
PUBLISH channel message发送消息,消费者使用SUBSCRIBE channel监听频道。 -
优点: 完美支持多消费者广播(一条消息可以让多个后台服务同时收到)。
-
致命缺点:
- 不支持数据持久化: 这是极其致命的!消息发送后“阅后即焚”,Redis 根本不会把它存下来。
- 消息丢失率极高: 如果消费者正好由于网络波动断开了连接,在断开期间生产者发的消息,消费者重新连上后永远也收不到了。
方案 3:基于 Stream (终极完美方案 🌟)
Stream 是 Redis 5.0 专门为了实现企业级消息队列而引入的全新数据类型。它汲取了 Kafka 的设计思想,完美避开了 List 和 Pub/Sub 的所有坑。
-
实现方式: 使用
XADD追加消息,使用XREAD或XREADGROUP读取消息。 -
优点:
- 绝对的数据持久化: 消息存入 Stream 后会一直保存在 Redis 内存/磁盘中,支持海量消息堆积。
- 支持消费者组 (Consumer Group): 允许多个消费者协同工作,加快消费速度,且保证一条消息只被组内的一个消费者处理。
- 内置 ACK 确认机制 (最强特性): 消费者处理完业务后,必须显式地向 Redis 发送一条
XACK确认指令。如果消费者拿到消息但中途宕机了没发 ACK,这条消息会被放入一个叫 PEL(Pending Entries List,待处理列表) 的地方,等待被重新消费,绝对保证消息不丢失!
三、 核心总结:三大方案对比表
面试官最喜欢让你对比这三种方案,这张表请务必刻在脑子里:
| 特性对比 | List 队列 | Pub/Sub 发布订阅 | Stream 消息队列 |
|---|---|---|---|
| 消息持久化 | 支持 (依赖 AOF/RDB) | 不支持 (阅后即焚) | 支持 (专为持久化设计) |
| 多消费者广播 | 不支持 (一对一) | 支持 (一对多) | 支持 (消费者组机制) |
| 阻塞读取 | 支持 (BRPOP) | 支持 | 支持 (XREAD BLOCK) |
| 消息确认机制 (ACK) | 不支持 (极易丢失) | 不支持 | 支持 (通过 PEL 保证不丢) |
| 总结评价 | 简陋的玩具 | 只适合做简单的实时通知 | Redis 官方指定的正统 MQ |