1. 今天做了什么
- 学习 Redis 消息队列的三种实现方式:基于 List、基于 PubSub、基于 Stream
- 学习 Stream 消息队列的 XREAD 命令及其优缺点
- 学习 Stream 消费者组的概念、命令和解决的问题
- 基于 Redis Stream 消息队列实现异步秒杀下单
2. 核心知识点
消息队列基础
- 消息队列(Message Queue):存储和管理消息,也被称为消息代理
- 为什么引入消息队列:
- 异步响应,提高速度
- 高峰时期大量请求先加入消息队列,后端按自己的处理能力匀速消耗
- 消息队列的基本要求:
- JVM 以外,不受 JVM 内存限制
- 对数据进行持久化,保证数据安全
- 保证消息有序性
- 消费者需要对消息进行确认,确保消息至少被消费一次
- 主流中间件有 RabbitMQ 等,这里使用 Redis 实现(3 种方式,了解即可)
方式一:基于 List 模拟
- 利用 BLPOP、BRPOP 来取数据,才具有阻塞效果
- 优点:基本满足前 3 条(存储在 Redis,可以持久化,list 是有序的)
- 缺点:
- 无法避免消息丢失,不满足第 4 条
- 只支持单消费者
方式二:基于 PubSub(发布订阅)
- Redis 发布订阅命令:
PUBLISH channel message:将信息发送到指定的频道PSUBSCRIBE pattern [pattern ...]:订阅一个或多个符合给定模式的频道SUBSCRIBE channel [channel ...]:订阅给定的一个或多个频道的信息
- 优点:采用发布订阅,支持多生产多消费者
- 缺点:无法保证数据安全
- 不支持持久化,无人订阅则丢失
- 无法避免消息丢失
- 消费者的消息堆积有上限,超出则丢失
方式三:基于 Stream 消息队列
- 发送与接收的命令(见截图)


- XREAD 命令读取优缺点:
- 消息永久保存,可回溯
- 可阻塞读取
- 有漏读问题($ 读取最新消息,如果处理一个消息过程中有消息到来则会漏读)
Stream 消费者组
- 消费者组可以解决 XREAD 漏读的问题
创建消费者组:
1 | XGROUP CREATE key groupName ID [MKSTREAM] |
其它常见命令:
1 | # 删除指定的消费者组 |
从消费者组读取消息:
1 | XREADGROUP GROUP group consumer [COUNT count] [BLOCK milliseconds] [NOACK] STREAMS key [key ...] ID [ID ...] |
消费者组解决了:
- 漏读问题,可以设置 “>” 从下一个未消费的消息开始
- 确认机制,未确认的消息保存在 pending-list,确保每个消息都被确认,防止消费者处理时异常导致消息丢失
- 一个消费者组中的消费者消费同一队列,可以提高效率
- 设置多个消费者组,可以实现多消费
实际选型建议
- 在实际开发中,list 与 PubSub 实现的消息队列缺点过多,不考虑
- 简单业务需求可以使用 Redis 的 Stream 消息队列
- 复杂场景,有复杂需求,还是要使用专业的中间件,如 RabbitMQ