实战篇 25. Redis 消息队列 - 认识 MQ 与方案对比 (学习文档)

3 阅读4分钟

📚 实战篇 25. Redis 消息队列 - 认识 MQ 与方案对比 (学习文档)

一、 什么是消息队列 (MQ)?

消息队列(Message Queue) ,字面意思就是存放消息的队列。最简单的消息队列模型包含三个核心角色:

  1. 生产者 (Producer): 负责生成消息并发送到队列中(比如我们的 Tomcat 主线程,负责生成订单号)。
  2. 消息代理 (Broker): 负责接收并存储消息,确保消息的安全和有序(比如我们要用的 Redis)。
  3. 消费者 (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 里消失了。如果消费者拿到消息还没来得及处理就宕机了,这条消息就永久丢失了!

方案 2:基于 Pub/Sub (发布订阅)

这是 Redis 专门为消息路由设计的模式。

  • 实现方式: 生产者使用 PUBLISH channel message 发送消息,消费者使用 SUBSCRIBE channel 监听频道。

  • 优点: 完美支持多消费者广播(一条消息可以让多个后台服务同时收到)。

  • 致命缺点:

    • 不支持数据持久化: 这是极其致命的!消息发送后“阅后即焚”,Redis 根本不会把它存下来。
    • 消息丢失率极高: 如果消费者正好由于网络波动断开了连接,在断开期间生产者发的消息,消费者重新连上后永远也收不到了

方案 3:基于 Stream (终极完美方案 🌟)

Stream 是 Redis 5.0 专门为了实现企业级消息队列而引入的全新数据类型。它汲取了 Kafka 的设计思想,完美避开了 List 和 Pub/Sub 的所有坑。

  • 实现方式: 使用 XADD 追加消息,使用 XREADXREADGROUP 读取消息。

  • 优点:

    • 绝对的数据持久化: 消息存入 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