消息队列概述
· 10 min read ·
—
一、什么是消息队列
定义:消息队列是在分布式系统组件间,以异步、可靠的方式传递消息的中间件。
核心比喻:饭店的传菜口台子。厨师(生产者)做好菜放台上,服务员(消费者)从台上取菜,两者互不干扰,完全解耦。
二、为什么需要消息队列?(三大核心作用)
| 作用 | 说明 | 典型场景 |
|---|---|---|
| 解耦 | 系统各组件只与消息交互,无需知道彼此存在 | 微服务间通信 |
| 异步 | 非关键任务后台慢慢处理,主流程快速返回 | 下单后发短信、邮件 |
| 削峰 | 瞬间高并发请求暂存起来,后台按节奏处理 | 秒杀、抢红包 |
一句话总结:消息队列是分布式系统的”信息高速公路服务区”,允许消息的发送方和接收方不直接对话、不同时在线。
三、核心概念
| 概念 | 一句话定义 | 类比 |
|---|---|---|
| 消息(Message) | 传递的数据包,包含业务数据和属性元数据 | 一封信(信封+信纸) |
| 生产者(Producer) | 创建并发送消息的应用程序 | 厨师 |
| 消费者(Consumer) | 接收并处理消息的应用程序 | 服务员 |
| 消息代理 (Broker) | 消息队列服务器,负责接收、存储、路由、投递 | 整个传菜口台子 |
| 主题(Topic) | 消息的逻辑分类标识 | 报纸刊名/公众号 |
| 队列(Queue) | 消息的暂存容器,FIFO(先进先出) | 传菜口台子上的一个格子 |
| 消费者组(Consumer Group) | 一组消费者的逻辑集合,组内竞争或组间广播 | 一个服务班组 |
| 死信队列(DLQ) | 无法被正常消费的消息的最终归宿,用于事后排查 | 废票回收箱 |
四、两种核心消息模型
点对点模型(P2P / Queue)
- 规则:一条消息只能被一个消费者成功消费,消费后不可再被其他消费者获取。
- 消费者关系:竞争关系,多人抢单。
- 主要用途:任务分发、负载均衡。
- 类比:客服工单系统——一个工单只能被一个客服处理。
Producer → Queue → Consumer1(抢到消息)
↓
Consumer2(等待下一条)
发布订阅模型(Pub/Sub / Topic)
- 规则:一条消息可以被多个订阅者同时消费,每人收到独立拷贝。
- 消费者关系:独立关系,各收各的。
- 主要用途:数据广播、一对多系统解耦。
- 类比:微信公众号推送——所有关注者都能看到同一篇文章。
Producer → Topic → Consumer1(收到全量消息)
→ Consumer2(收到全量消息)
→ Consumer3(收到全量消息)
五、一条消息的通用旅程
所有消息队列的可靠传输,本质上都是这四个阶段的排列组合:
阶段一:发送入队 阶段三:投递消费
Producer ──────▶ Broker ──────▶ Consumer
▲ │ │
└─ 生产端确认 ◀──┘ 消费端确认 ──┘
(阶段二:持久化存储) (阶段四:确认清理)
阶段一:发送与接收入队
| 要素 | 说明 |
|---|---|
| 做什么 | 生产者将消息发送给 Broker,Broker 接收并放入内部存储 |
| 生产者动作 | 指定消息体 + 路由目标(Topic 名 / 队列名) |
| Broker 动作 | 接收消息,返回确认信号 |
| 通用机制 | 生产端确认:所有 MQ 都有,生产者据此判断消息是否成功入队 |
阶段二:持久化存储
| 要素 | 说明 |
|---|---|
| 做什么 | Broker 将消息写入磁盘,保证宕机不丢失,等待投递 |
| 通用机制 | 消息持久化:所有 MQ 都支持,是可选的配置项(性能 vs 可靠性的权衡) |
阶段三:投递与消费
| 要素 | 说明 |
|---|---|
| 做什么 | Broker 将消息交给消费者,消费者执行业务逻辑 |
| 投递方式 | Push(Broker 推送)或 Pull(消费者拉取),不同产品默认不同 |
| 通用要求 | 幂等性:业务逻辑必须能容忍重复消费,保证”多次执行 = 一次效果” |
阶段四:确认与清理
| 要素 | 说明 |
|---|---|
| 做什么 | 消费者处理成功后,通知 Broker;Broker 标记或删除该消息 |
| 消费者动作 | 发送”处理完成”的信号 |
| Broker 动作 | 删除消息(RabbitMQ),或推进消费位移 Offset(Kafka / RocketMQ) |
| 失败处理 | 超过重试上限的消息进入死信队列 |
| 通用机制 | 消费端确认:所有 MQ 都有,区别在于自动/手动、提交方式 |
六、主流消息队列对比
| 产品 | 特点 | 单机吞吐量 | 适用场景 |
|---|---|---|---|
| RabbitMQ | 功能完善、支持多种协议、社区活跃 | ~1 万条/秒 | 中小规模应用、高可靠性场景 |
| Kafka | 高吞吐、分布式、日志型存储 | ~100 万条/秒 | 大数据、日志收集、流计算 |
| RocketMQ | 阿里开源、金融级可靠性、事务消息 | ~10 万条/秒 | 业务系统、电商、金融 |
选型建议:
- 新手入门推荐 RabbitMQ,先吃透消息模型和可靠性机制。
- 大数据、高吞吐场景首选 Kafka。
- 金融、电商等对事务有强需求的,考虑 RocketMQ。
七、消息队列的优缺点
优点
- 解耦:系统边界清晰,修改扩展更安全。
- 异步:提升用户体验,非核心任务后台处理。
- 削峰:保护下游系统,应对突发流量。
缺点
- 系统复杂度提高:需要额外维护 Broker 集群。
- 可用性降低:Broker 宕机会影响所有依赖它的系统。
- 一致性问题:消息丢失或重复消费可能导致数据不一致。
应对措施(对应四种通用机制):
- 消息丢失 → 生产端确认 + 消息持久化 + 消费端手动确认
- 重复消费 → 幂等性设计(数据库唯一键、Redis 去重等)
- 消费失败 → 死信队列兜底,方便人工排查和补偿
八、一图总结
┌──────────┐ ① 发送消息 ┌──────────┐ ③ 投递消费 ┌──────────┐
│ Producer │ ────────────────▶ │ Broker │ ──────────────▶ │ Consumer │
└──────────┘ └──────────┘ └──────────┘
▲ │ │ │
│ ② 持久化 + 生产端确认 │ │ ④ 消费端确认 + 清理 │
└────────────────────────────┘ └───────────────────────────┘
● 失败重试 → 死信队列