Redis 三种消息队列实现方案

为什么需要消息队列?

1. 系统解耦(最核心目的)

传统同步调用:A 服务直接调用 B、C、D 服务,接口强依赖,任意下游宕机、改接口都会导致 A 报错,代码耦合严重。 引入 MQ 后:生产者只发送消息到队列,无需关心谁消费、如何处理;消费者自主拉取消息,上下游完全隔离。 新增 / 删除下游业务,生产者代码零改动。

2. 削峰填谷,抗流量突发

秒杀、活动大促、定时任务瞬间产生海量请求,数据库、接口瞬时并发压垮,直接超时、崩溃。

  • 峰值:流量全部存入消息队列,不会直接冲击底层服务;
  • 谷值:消费端匀速慢慢处理堆积消息,平稳消化流量,保护数据库、接口不被打崩。

3. 异步处理,提升主接口响应速度

很多业务存在非实时附属操作:下单后发短信、发优惠券、日志记录、物流通知、数据统计。 同步方案:用户下单要等短信、统计全部执行完才返回,接口耗时高,用户等待卡顿。 MQ 异步方案:下单主逻辑完成立刻返回结果,后续附属任务丢进队列后台异步执行,大幅缩短主流程 RT,优化用户体验。

4. 最终一致性,保证可靠事务

分布式多服务场景下,同步调用容易出现部分成功、部分失败的数据不一致问题(下单成功但库存扣减失败)。 利用 MQ 可靠投递、死信队列、事务消息,实现分布式事务兜底,保证多服务业务要么全部完成,要么补偿回滚,避免数据错乱。

5. 消息复用,多消费广播

一条业务消息可被多个消费者同时消费:订单创建消息,订单服务、积分服务、推送服务、数据分析服务各自监听,一份数据源支撑多业务,不用重复生产、重复查询数据库。

Redis消息队列?

在秒杀、异步通知、解耦削峰等业务场景中,消息队列是核心基础设施。如果项目已经重度依赖 Redis,无需额外部署 RocketMQ、RabbitMQ 等专业中间件,可直接基于 Redis 原生数据结构快速实现简易消息队列。

Redis 提供了三套原生消息模型:双向链表 List、发布订阅 PubSub、流式数据结构 Stream。三者底层实现、适用场景、可靠性差距极大,本文结合底层原理、优缺点、业务落地场景完整拆解对比。

一、基于 List 双向链表实现消息队列

1. 底层实现原理

Redis List 是双向链表,支持两端读写,天然满足队列「先进先出」特性。

  • 生产者入队:LPUSH queue msg(左侧写入消息)
  • 消费者出队:RPOP queue(右侧读取消息)
  • 阻塞等待优化:普通 RPOP 无消息直接返回 nil,需循环轮询浪费 CPU;使用 BRPOP queue timeout 实现阻塞读取,无消息时线程挂起,有消息自动唤醒。

2. 核心优势

  1. 支持持久化 List 属于普通 Redis Key,开启 RDB/AOF 持久化后,消息落盘存储,Redis 宕机重启消息不会丢失。
  2. 不受 JVM 内存限制 消息存储在 Redis 服务端内存,区别于 Java 内置阻塞队列,集群多实例可共用同一队列。
  3. 天然有序 链表按入队顺序存储,严格保证消息 FIFO 顺序,适合有序处理场景。

3. 缺点

  1. 仅支持单消费者 一条消息执行 RPOP 后会直接从链表删除,多个消费者竞争队列时,消息只会被其中一个线程消费,无法实现多消费者并行消费;若要多实例扩容,只能手动拆分多个队列。
  2. 无消息 ACK 确认机制 消息一旦弹出队列就永久删除,若消费者读取消息后宕机,业务逻辑未执行完成,消息直接丢失,无法重试。
  3. 无法回溯历史消息 消息消费完成即删除,不能重新读取历史消息,排查故障、数据补偿场景受限。

4. 适用场景

低并发、单实例消费、允许少量消息丢失的轻量异步场景,例如简单日志同步、本地缓存刷新通知。

二、基于 PubSub 发布订阅模型实现消息队列

1. 底层实现原理

Redis 2.0 推出发布订阅机制,采用一对多广播模型:

  • 生产者:PUBLISH channel msg 向指定频道推送消息
  • 消费者:SUBSCRIBE channel 订阅频道,频道消息会推送给所有订阅客户端
  • 模式匹配:PSUBSCRIBE order.* 模糊匹配多个频道,实现通配订阅

一条消息发布后,所有在线订阅者都会收到完整消息,属于广播模式。

2. 核心优势

  1. 原生多生产者、多消费者广播 一条消息可同时下发给多个消费者,适用于通知同步场景(如订单完成后同步通知积分、物流、短信多个服务)。
  2. 天然阻塞等待 订阅后客户端持续阻塞,频道有消息实时推送,无需手动轮询。

3. 缺点

  1. 完全不支持持久化 PubSub 消息仅存在 Redis 瞬时缓冲区,不落地磁盘。消费者离线期间生产者发送的消息会直接丢弃,重启后无法补收离线消息。
  2. 无消息堆积能力 消费者消费速度跟不上生产速度时,缓冲区溢出会直接丢弃消息;没有持久存储层做消息缓冲。
  3. 无 ACK 确认、消息丢失风险高 消息推送完成即丢弃,消费者宕机、网络抖动都会丢失消息,无法重试。

4. 适用场景

实时广播通知、对消息可靠性无要求的实时推送场景,例如在线状态推送、实时前端消息通知,不适合订单、支付等核心业务。

三、基于 Stream 流式结构实现消息队列

1. 底层实现原理

Stream 是 Redis 5.0 专为消息队列设计的数据结构,底层是有序日志流,每条消息携带唯一自增 ID 永久存储,配套消费者组 Consumer Group 实现可靠消费。 核心配套命令:

  1. 生产者写入:XADD queue * k1 v1 写入消息,自动生成唯一 ID
  2. 阻塞消费:XREADGROUP GROUP g1 c1 BLOCK 0 STREAMS queue > 消费者组阻塞读取消息
  3. 消息确认:XACK queue g1 msgId 业务处理完成后手动确认消息
  4. 消息回溯:可通过指定历史 ID,重新读取任意历史消息

2. 消费者组三大核心能力

(1)消息分流(多消费者并行消费)

同一个消费者组内多个消费者监听同一 Stream,消息会分摊给组内不同消费者,一条消息仅被一个消费者处理,实现消费扩容,提升处理速度。

(2)消费位点持久化记录

消费者组会持久记录当前消费到的消息 ID,服务宕机重启后,会从上次未处理完成的消息继续读取,不会漏消费。

(3)Pending-List 消息确认机制

消费者读取消息后,消息会存入待确认列表(Pending-List),不会直接删除;必须手动执行 XACK 标记处理完成,才会移除待确认状态。 若消费者宕机、超时未确认,其他消费者可接管该消息重试,保证消息至少被消费一次

3. 核心优势

  1. 支持持久化存储 Stream 消息完整落盘,Redis 重启不丢失历史消息,支持配置消息过期时间控制存储容量。
  2. 完备 ACK 确认机制,可靠性强 待确认列表 + XACK 手动确认,杜绝消费宕机导致的消息丢失,支持消息重试。
  3. 支持消息回溯 可指定任意历史消息 ID 读取日志,故障排查、数据补偿场景友好。
  4. 阻塞读取 + 多消费者扩容 支持阻塞等待消息;消费者组实现负载均衡,多实例并行消费,解决消息堆积。

4. 缺点

  1. 架构复杂度高于 List、PubSub,需要维护消费者组、手动处理 ACK、超时未确认消息;
  2. 存在消息重复消费可能(至少一次语义),业务侧需要做幂等处理。

5. 适用场景

生产级可靠异步场景,秒杀削峰、订单异步处理、优惠券发放、数据同步等核心业务,是 Redis 实现消息队列的最优方案。

四、三种方式对比

对比维度 List PubSub Stream
消息持久化 支持 不支持 支持
阻塞读取 BRPOP 支持 SUBSCRIBE 原生阻塞 XREADGROUP 支持
多消费者并行消费 不支持,单消费 广播模式,全部接收 消费者组分流,负载均衡
ACK 确认机制 有 XACK 确认、Pending 列表
消息回溯 不支持,消费即删除 不支持,离线消息丢失 支持,可读取任意历史消息
消息丢失风险 中等(宕机未处理丢失) 极高(离线、堆积全部丢失) 极低(至少消费一次)
消息堆积能力 依赖 Redis 内存上限 缓冲区极小,极易丢消息 支持长期堆积,可配置过期
适用可靠性等级 低可靠非核心业务 实时广播、低可靠通知 高可靠核心异步业务

如何选择?

  1. 简单轻量异步、单实例、无可靠性要求 → List 队列 例如本地缓存刷新、简单日志异步打印,开发成本最低。
  2. 多服务实时广播通知、不在乎消息丢失 → PubSub 例如直播间在线人数推送、前端实时弹窗通知。
  3. 秒杀削峰、订单异步、支付回调、核心业务解耦 → Stream 消费者组 生产环境首选,兼顾持久化、可靠 ACK、多实例扩容,是 Redis 官方标准消息队列实现。
相关推荐
智购科技智能售货柜1 小时前
自动售货机商品识别YOLO模型训练实战:从6万张图片到98%识别率的完整复盘~YH
运维·服务器·数据库·人工智能·redis·物联网·yolo
ACP广源盛139246256731 小时前
2026 PCIe互连芯片@ACP#国产替代格局解析:芯动科技领跑高端交换芯片赛道
大数据·网络·数据库·人工智能·分布式·嵌入式硬件
代码代码快快显灵1 小时前
MYSQL-DAY2
数据库·mysql
隔窗听雨眠2 小时前
Oracle到PostgreSQL迁移实战:pg_hint_plan执行计划控制完全指南
数据库·postgresql·oracle
IKUN家族2 小时前
常见的依懒
java·服务器·数据库
DBA_G2 小时前
解析GBase 8s数据库锁机制
数据库·oracle
captain3762 小时前
多线程进阶
java·开发语言·数据库
initialize13062 小时前
Oracle数据库 binary XML data类型同步
xml·数据库
倔强的石头1062 小时前
连接池参数治理-HikariCP怎么配才稳
数据库·oracle