06-17-A-RabbitMQ架构与存储原理详解
️ 关键词:RabbitMQ · AMQP · Exchange · Queue · Binding · Routing Key · VHost · Erlang · 经典队列 · Quorum Queue · Stream · 内存与磁盘存储
📌 导读 :三大消息队列里,RabbitMQ 是"路由最灵活 "的那个------Kafka 靠 Partition 哈希路由,RocketMQ 靠 Topic+Tag,而 RabbitMQ 靠 Exchange + Binding Key 的组合路由 ,能把一条消息按规则分发到任意多个队列。RabbitMQ 系列共四篇:本篇讲"架构与存储"(AMQP 模型、Exchange/Queue/Binding 三件套、VHost、队列的内存/磁盘存储机制、三种队列类型),10 篇讲"消息特性与消费机制"(四种 Exchange 路由、确认机制、TTL/DLX/延迟队列、消费与 prefetch),11 篇讲"高可用与生产调优"(镜像队列/Quorum Queue、集群、参数调优、积压处理),12 篇是面试与生产事故实战。看完本篇你能做到:被问"RabbitMQ 路由模型"能画出 Producer→Exchange→Binding→Queue→Consumer 图,被问"消息什么时候落盘"能讲出内存队列+惰性持久化,被问"经典队列和 Quorum Queue 怎么选"能给出对比表。
📑 目录
- 06-17-A-RabbitMQ架构与存储原理详解
-
- [📖 术语速查表(每个词都用人话解释)](#📖 术语速查表(每个词都用人话解释))
- [一、RabbitMQ 的定位:路由最灵活的 MQ](#一、RabbitMQ 的定位:路由最灵活的 MQ)
-
- [1.1 三大 MQ 分工](#1.1 三大 MQ 分工)
- [1.2 为什么路由灵活是核心优势](#1.2 为什么路由灵活是核心优势)
- 二、核心模型:Exchange、Queue、Binding
-
- [2.1 消息流转模型](#2.1 消息流转模型)
- [2.2 Connection 与 Channel:多路复用](#2.2 Connection 与 Channel:多路复用)
- [2.3 与 Kafka/RocketMQ 的模型对比](#2.3 与 Kafka/RocketMQ 的模型对比)
- 三、存储机制:消息什么时候在内存、什么时候在磁盘
-
- [3.1 经典队列的存储策略](#3.1 经典队列的存储策略)
- [3.2 三种队列类型选型](#3.2 三种队列类型选型)
- [3.3 磁盘目录结构](#3.3 磁盘目录结构)
- 四、集群架构:元数据与消息的分布
-
- [4.1 集群的默认行为](#4.1 集群的默认行为)
- [4.2 磁盘节点与内存节点](#4.2 磁盘节点与内存节点)
- [4.3 客户端连接策略](#4.3 客户端连接策略)
- 五、跑一遍:从启动到观察路由与存储
-
- [5.1 启动与声明拓扑](#5.1 启动与声明拓扑)
- [5.2 发消息观察路由](#5.2 发消息观察路由)
- [5.3 消费与"消费即删"验证](#5.3 消费与"消费即删"验证)
- 六、总结
-
- [6.1 一张图回顾全文](#6.1 一张图回顾全文)
- [6.2 核心要点浓缩(十二条)](#6.2 核心要点浓缩(十二条))
📖 术语速查表(每个词都用人话解释)
** AMQP 模型类**
| 术语 | 一句话白话解释 |
|---|---|
| AMQP | Advanced Message Queuing Protocol------RabbitMQ 实现的开放消息协议,定义了 Producer/Exchange/Queue/Consumer 的标准交互 |
| RabbitMQ | Erlang 写的 AMQP Broker------路由专家,万级 TPS,管理界面好用,中小规模业务首选 |
| Producer | 消息生产者------发消息到 Exchange(注意:不是直接发 Queue) |
| Exchange(交换机) | 消息的"路由器"------接收 Producer 消息,按 Binding 规则分发到 Queue ------RabbitMQ 的核心抽象,自己不存消息 |
| Queue(队列) | 消息的"缓冲区"------存储消息,Consumer 从 Queue 消费------消息真正的家 |
| Binding(绑定) | Exchange 和 Queue 之间的路由规则------含 Binding Key,决定什么消息进什么 Queue |
| Routing Key | 消息的路由键------Producer 发消息时指定,Exchange 用它匹配 Binding |
| Binding Key | 绑定的匹配模式------Exchange 用 Routing Key 匹配 Binding Key,命中则投递到对应 Queue |
| VHost(虚拟主机) | 逻辑隔离的"命名空间"------不同 VHost 的 Exchange/Queue 完全隔离(类似数据库的 schema) |
| Connection / Channel | TCP 连接 / 连接内的逻辑通道------一个 Connection 多路复用多个 Channel(省 TCP 握手,线程级隔离) |
| 默认 Exchange | 名为 ""(空串)的 direct Exchange------每个 Queue 自动以队列名绑定 ,basicPublish("", "queueName") 直达队列 |
️ 存储类
| 术语 | 一句话白话解释 |
|---|---|
| 经典队列(Classic Queue) | 传统队列实现------消息优先放内存,内存压力/持久化消息才写磁盘(v1/v2 两代存储引擎) |
| Quorum Queue | 3.8+ 的基于 Raft 的高可用队列 ------多数派写入不丢数据,替代镜像队列(3.12 起官方推荐) |
| Stream | 3.9+ 的日志型队列 ------追加写、可重复消费、百万级吞吐------Kafka 化的 RabbitMQ(日志/流场景) |
| 持久化(durable) | Exchange/Queue 元数据落盘 + 消息 deliveryMode=2------Broker 重启不丢 |
| 惰性队列(Lazy Queue) | 消息直接写磁盘不进内存------百万级积压不撑爆内存(3.12+ 经典队列默认惰性行为) |
| Page 机制 | 经典队列把磁盘消息按页(32MB)组织------paging 到磁盘、内存只留索引 |
一、RabbitMQ 的定位:路由最灵活的 MQ
1.1 三大 MQ 分工
| 维度 | RabbitMQ | RocketMQ | Kafka |
|---|---|---|---|
| 协议 | AMQP(开放协议) | 自研 | 自研 |
| 语言 | Erlang | Java | Scala/Java |
| 路由 | Exchange+Binding 组合路由(最灵活) | Topic+Tag | Partition 哈希 |
| 延迟消息 | ✅ TTL+DLX(任意时间)/ 延迟插件 | ✅ 18 等级(5.x 任意时间) | ❌(生态方案) |
| 吞吐 | 万级 TPS | 十万级 TPS | 百万级 TPS |
| 消息回溯 | ❌(消费即删) | ✅(按时间/位点) | ✅(按 Offset) |
| 生态 | 多语言(AMQP 标准)、管理界面好 | Java/阿里云生态 | 大数据生态 |
| 适用 | 中小规模、路由复杂、多语言 | 业务消息(事务/延迟) | 日志/流处理/大数据 |
一句话 :RabbitMQ 是"路由专家"------Exchange+Binding 的组合路由最灵活,AMQP 开放协议多语言友好;吞吐不如 Kafka/RocketMQ,适合中小规模+复杂路由场景(完整对比见 26-A 篇)。
1.2 为什么路由灵活是核心优势
#mermaid-svg-APfB2SIkKNANhSBv{font-family:Microsoft YaHei;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-APfB2SIkKNANhSBv .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-APfB2SIkKNANhSBv .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-APfB2SIkKNANhSBv .error-icon{fill:hsl(220.5882352941, 100%, 98.3333333333%);}#mermaid-svg-APfB2SIkKNANhSBv .error-text{fill:rgb(8.5000000002, 5.7500000001, 0);stroke:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-APfB2SIkKNANhSBv .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-APfB2SIkKNANhSBv .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-APfB2SIkKNANhSBv .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-APfB2SIkKNANhSBv .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-APfB2SIkKNANhSBv .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-APfB2SIkKNANhSBv .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-APfB2SIkKNANhSBv .marker{fill:#0b0b0b;stroke:#0b0b0b;}#mermaid-svg-APfB2SIkKNANhSBv .marker.cross{stroke:#0b0b0b;}#mermaid-svg-APfB2SIkKNANhSBv svg{font-family:Microsoft YaHei;font-size:16px;}#mermaid-svg-APfB2SIkKNANhSBv p{margin:0;}#mermaid-svg-APfB2SIkKNANhSBv .label{font-family:Microsoft YaHei;color:#333;}#mermaid-svg-APfB2SIkKNANhSBv .cluster-label text{fill:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-APfB2SIkKNANhSBv .cluster-label span{color:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-APfB2SIkKNANhSBv .cluster-label span p{background-color:transparent;}#mermaid-svg-APfB2SIkKNANhSBv .label text,#mermaid-svg-APfB2SIkKNANhSBv span{fill:#333;color:#333;}#mermaid-svg-APfB2SIkKNANhSBv .node rect,#mermaid-svg-APfB2SIkKNANhSBv .node circle,#mermaid-svg-APfB2SIkKNANhSBv .node ellipse,#mermaid-svg-APfB2SIkKNANhSBv .node polygon,#mermaid-svg-APfB2SIkKNANhSBv .node path{fill:#fff4dd;stroke:hsl(40.5882352941, 60%, 83.3333333333%);stroke-width:1px;}#mermaid-svg-APfB2SIkKNANhSBv .rough-node .label text,#mermaid-svg-APfB2SIkKNANhSBv .node .label text,#mermaid-svg-APfB2SIkKNANhSBv .image-shape .label,#mermaid-svg-APfB2SIkKNANhSBv .icon-shape .label{text-anchor:middle;}#mermaid-svg-APfB2SIkKNANhSBv .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-APfB2SIkKNANhSBv .rough-node .label,#mermaid-svg-APfB2SIkKNANhSBv .node .label,#mermaid-svg-APfB2SIkKNANhSBv .image-shape .label,#mermaid-svg-APfB2SIkKNANhSBv .icon-shape .label{text-align:center;}#mermaid-svg-APfB2SIkKNANhSBv .node.clickable{cursor:pointer;}#mermaid-svg-APfB2SIkKNANhSBv .root .anchor path{fill:#0b0b0b!important;stroke-width:0;stroke:#0b0b0b;}#mermaid-svg-APfB2SIkKNANhSBv .arrowheadPath{fill:#0b0b0b;}#mermaid-svg-APfB2SIkKNANhSBv .edgePath .path{stroke:#0b0b0b;stroke-width:2.0px;}#mermaid-svg-APfB2SIkKNANhSBv .flowchart-link{stroke:#0b0b0b;fill:none;}#mermaid-svg-APfB2SIkKNANhSBv .edgeLabel{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);text-align:center;}#mermaid-svg-APfB2SIkKNANhSBv .edgeLabel p{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-APfB2SIkKNANhSBv .edgeLabel rect{opacity:0.5;background-color:hsl(-79.4117647059, 100%, 93.3333333333%);fill:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-APfB2SIkKNANhSBv .labelBkg{background-color:rgba(243.9999999999, 220.9999999998, 255, 0.5);}#mermaid-svg-APfB2SIkKNANhSBv .cluster rect{fill:hsl(220.5882352941, 100%, 98.3333333333%);stroke:hsl(220.5882352941, 60%, 88.3333333333%);stroke-width:1px;}#mermaid-svg-APfB2SIkKNANhSBv .cluster text{fill:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-APfB2SIkKNANhSBv .cluster span{color:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-APfB2SIkKNANhSBv div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:Microsoft YaHei;font-size:12px;background:hsl(220.5882352941, 100%, 98.3333333333%);border:1px solid hsl(220.5882352941, 60%, 88.3333333333%);border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-APfB2SIkKNANhSBv .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-APfB2SIkKNANhSBv rect.text{fill:none;stroke-width:0;}#mermaid-svg-APfB2SIkKNANhSBv .icon-shape,#mermaid-svg-APfB2SIkKNANhSBv .image-shape{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);text-align:center;}#mermaid-svg-APfB2SIkKNANhSBv .icon-shape p,#mermaid-svg-APfB2SIkKNANhSBv .image-shape p{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);padding:2px;}#mermaid-svg-APfB2SIkKNANhSBv .icon-shape .label rect,#mermaid-svg-APfB2SIkKNANhSBv .image-shape .label rect{opacity:0.5;background-color:hsl(-79.4117647059, 100%, 93.3333333333%);fill:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-APfB2SIkKNANhSBv .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-APfB2SIkKNANhSBv .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-APfB2SIkKNANhSBv :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 一条消息,按规则分发到多个 Queue。
fanout:广播到所有 Queue。
订单事件 → 库存 / 积分 /
通知 / 日志。
topic:按模式匹配。
order.create → 订单 Queue。
order.* → 所有订单相关 Queue。
#.error → 所有错误 Queue。
direct:精确路由。
pay.success → 支付 Queue。
Kafka / RocketMQ 做不到:
一条消息按不同规则进不同 Queue。
RabbitMQ 的 Exchange
是天然的路由层。
对比理解 :Kafka/RocketMQ 的"发布订阅"靠多个 Consumer Group 各自消费同一 Topic (消息复制给每个组);RabbitMQ 靠一条消息路由进多个 Queue (消息在 Broker 内复制)。前者订阅方决定,后者路由规则决定------RabbitMQ 的路由规则可以集中管理、动态修改,不用动生产者和消费者代码。
二、核心模型:Exchange、Queue、Binding
2.1 消息流转模型
#mermaid-svg-agmbP2EU3OarsKb6{font-family:Microsoft YaHei;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-agmbP2EU3OarsKb6 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-agmbP2EU3OarsKb6 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-agmbP2EU3OarsKb6 .error-icon{fill:hsl(220.5882352941, 100%, 98.3333333333%);}#mermaid-svg-agmbP2EU3OarsKb6 .error-text{fill:rgb(8.5000000002, 5.7500000001, 0);stroke:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-agmbP2EU3OarsKb6 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-agmbP2EU3OarsKb6 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-agmbP2EU3OarsKb6 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-agmbP2EU3OarsKb6 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-agmbP2EU3OarsKb6 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-agmbP2EU3OarsKb6 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-agmbP2EU3OarsKb6 .marker{fill:#0b0b0b;stroke:#0b0b0b;}#mermaid-svg-agmbP2EU3OarsKb6 .marker.cross{stroke:#0b0b0b;}#mermaid-svg-agmbP2EU3OarsKb6 svg{font-family:Microsoft YaHei;font-size:16px;}#mermaid-svg-agmbP2EU3OarsKb6 p{margin:0;}#mermaid-svg-agmbP2EU3OarsKb6 .label{font-family:Microsoft YaHei;color:#333;}#mermaid-svg-agmbP2EU3OarsKb6 .cluster-label text{fill:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-agmbP2EU3OarsKb6 .cluster-label span{color:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-agmbP2EU3OarsKb6 .cluster-label span p{background-color:transparent;}#mermaid-svg-agmbP2EU3OarsKb6 .label text,#mermaid-svg-agmbP2EU3OarsKb6 span{fill:#333;color:#333;}#mermaid-svg-agmbP2EU3OarsKb6 .node rect,#mermaid-svg-agmbP2EU3OarsKb6 .node circle,#mermaid-svg-agmbP2EU3OarsKb6 .node ellipse,#mermaid-svg-agmbP2EU3OarsKb6 .node polygon,#mermaid-svg-agmbP2EU3OarsKb6 .node path{fill:#fff4dd;stroke:hsl(40.5882352941, 60%, 83.3333333333%);stroke-width:1px;}#mermaid-svg-agmbP2EU3OarsKb6 .rough-node .label text,#mermaid-svg-agmbP2EU3OarsKb6 .node .label text,#mermaid-svg-agmbP2EU3OarsKb6 .image-shape .label,#mermaid-svg-agmbP2EU3OarsKb6 .icon-shape .label{text-anchor:middle;}#mermaid-svg-agmbP2EU3OarsKb6 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-agmbP2EU3OarsKb6 .rough-node .label,#mermaid-svg-agmbP2EU3OarsKb6 .node .label,#mermaid-svg-agmbP2EU3OarsKb6 .image-shape .label,#mermaid-svg-agmbP2EU3OarsKb6 .icon-shape .label{text-align:center;}#mermaid-svg-agmbP2EU3OarsKb6 .node.clickable{cursor:pointer;}#mermaid-svg-agmbP2EU3OarsKb6 .root .anchor path{fill:#0b0b0b!important;stroke-width:0;stroke:#0b0b0b;}#mermaid-svg-agmbP2EU3OarsKb6 .arrowheadPath{fill:#0b0b0b;}#mermaid-svg-agmbP2EU3OarsKb6 .edgePath .path{stroke:#0b0b0b;stroke-width:2.0px;}#mermaid-svg-agmbP2EU3OarsKb6 .flowchart-link{stroke:#0b0b0b;fill:none;}#mermaid-svg-agmbP2EU3OarsKb6 .edgeLabel{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);text-align:center;}#mermaid-svg-agmbP2EU3OarsKb6 .edgeLabel p{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-agmbP2EU3OarsKb6 .edgeLabel rect{opacity:0.5;background-color:hsl(-79.4117647059, 100%, 93.3333333333%);fill:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-agmbP2EU3OarsKb6 .labelBkg{background-color:rgba(243.9999999999, 220.9999999998, 255, 0.5);}#mermaid-svg-agmbP2EU3OarsKb6 .cluster rect{fill:hsl(220.5882352941, 100%, 98.3333333333%);stroke:hsl(220.5882352941, 60%, 88.3333333333%);stroke-width:1px;}#mermaid-svg-agmbP2EU3OarsKb6 .cluster text{fill:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-agmbP2EU3OarsKb6 .cluster span{color:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-agmbP2EU3OarsKb6 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:Microsoft YaHei;font-size:12px;background:hsl(220.5882352941, 100%, 98.3333333333%);border:1px solid hsl(220.5882352941, 60%, 88.3333333333%);border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-agmbP2EU3OarsKb6 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-agmbP2EU3OarsKb6 rect.text{fill:none;stroke-width:0;}#mermaid-svg-agmbP2EU3OarsKb6 .icon-shape,#mermaid-svg-agmbP2EU3OarsKb6 .image-shape{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);text-align:center;}#mermaid-svg-agmbP2EU3OarsKb6 .icon-shape p,#mermaid-svg-agmbP2EU3OarsKb6 .image-shape p{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);padding:2px;}#mermaid-svg-agmbP2EU3OarsKb6 .icon-shape .label rect,#mermaid-svg-agmbP2EU3OarsKb6 .image-shape .label rect{opacity:0.5;background-color:hsl(-79.4117647059, 100%, 93.3333333333%);fill:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-agmbP2EU3OarsKb6 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-agmbP2EU3OarsKb6 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-agmbP2EU3OarsKb6 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Binding Key = order.create
Binding Key = order.*
Binding Key = #.error
Producer。
发消息 + Routing Key。
Exchange。
路由器,按 Binding 分发。
Queue1:订单处理。
Queue2:订单统计。
Queue3:错误告警。
Consumer1。
Consumer2。
Consumer3。
关键认知:
- Producer 不直接发 Queue------Producer 发消息到 Exchange,由 Exchange 按 Binding 路由到 Queue;
- Exchange 是路由器,Queue 是缓冲区------Exchange 不存消息(只路由),Queue 存消息;
- 一条消息可进多个 Queue------fanout/topic 下一条消息匹配多个 Binding,复制到多个 Queue;
- 路由不到任何 Queue 的消息 ------默认直接丢弃 !要开启
mandatory=true(退回 Producer)或配 **备用交换机(Alternate Exchange)**兜底(10 篇详解); - VHost 隔离------不同 VHost 的 Exchange/Queue 完全隔离(多租户/多环境)。
2.2 Connection 与 Channel:多路复用
text
应用服务器 ──1 个 TCP Connection──> RabbitMQ
├── Channel 1(线程 A:发订单消息)
├── Channel 2(线程 B:发支付消息)
└── Channel 3(线程 C:消费队列)
| 概念 | 说明 |
|---|---|
| Connection | TCP 长连接------建立成本高(握手+认证),一个应用 1~2 个就够 |
| Channel | Connection 内的逻辑通道------AMQP 命令都在 Channel 上走,轻量(无 TCP 开销) |
| 军规 | Channel 非线程安全------每个线程用自己的 Channel(Spring AMQP 的 RabbitTemplate 已做线程安全封装) |
2.3 与 Kafka/RocketMQ 的模型对比
| RabbitMQ | RocketMQ | Kafka | |
|---|---|---|---|
| 路由层 | Exchange(独立路由器) | Broker 内 Topic+Tag | Broker 内 Partition 哈希 |
| 消息存储 | Queue(消费即删) | CommitLog+ConsumeQueue(按时间保留) | Partition 日志(按 retention 保留) |
| 一条消息多 Queue | ✅(fanout/topic) | ❌(一个 Topic 一份) | ❌(一个 Partition 一份) |
| 消费模型 | 推模式(Broker push 给 Consumer) | 长轮询拉 | 拉模式(poll) |
| 消息回溯 | ❌ 消费即删 | ✅ | ✅ |
| 并行单位 | Queue(一个 Queue 可多 Consumer 轮询) | Message Queue | Partition |
本质差异 :RabbitMQ 是"智能 Broker + 哑 Queue "(路由逻辑在 Broker 的 Exchange),Kafka 是"哑 Broker + 智能 Consumer "(路由逻辑在 Producer 的分区器,消费进度在 Consumer)------灵活性给了 Broker,吞吐就受限;逻辑下放两端,Broker 就能做薄做快。
三、存储机制:消息什么时候在内存、什么时候在磁盘
3.1 经典队列的存储策略
#mermaid-svg-MfqRIz15fboL8IuH{font-family:Microsoft YaHei;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MfqRIz15fboL8IuH .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MfqRIz15fboL8IuH .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MfqRIz15fboL8IuH .error-icon{fill:hsl(220.5882352941, 100%, 98.3333333333%);}#mermaid-svg-MfqRIz15fboL8IuH .error-text{fill:rgb(8.5000000002, 5.7500000001, 0);stroke:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-MfqRIz15fboL8IuH .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MfqRIz15fboL8IuH .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MfqRIz15fboL8IuH .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MfqRIz15fboL8IuH .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MfqRIz15fboL8IuH .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MfqRIz15fboL8IuH .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MfqRIz15fboL8IuH .marker{fill:#0b0b0b;stroke:#0b0b0b;}#mermaid-svg-MfqRIz15fboL8IuH .marker.cross{stroke:#0b0b0b;}#mermaid-svg-MfqRIz15fboL8IuH svg{font-family:Microsoft YaHei;font-size:16px;}#mermaid-svg-MfqRIz15fboL8IuH p{margin:0;}#mermaid-svg-MfqRIz15fboL8IuH .label{font-family:Microsoft YaHei;color:#333;}#mermaid-svg-MfqRIz15fboL8IuH .cluster-label text{fill:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-MfqRIz15fboL8IuH .cluster-label span{color:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-MfqRIz15fboL8IuH .cluster-label span p{background-color:transparent;}#mermaid-svg-MfqRIz15fboL8IuH .label text,#mermaid-svg-MfqRIz15fboL8IuH span{fill:#333;color:#333;}#mermaid-svg-MfqRIz15fboL8IuH .node rect,#mermaid-svg-MfqRIz15fboL8IuH .node circle,#mermaid-svg-MfqRIz15fboL8IuH .node ellipse,#mermaid-svg-MfqRIz15fboL8IuH .node polygon,#mermaid-svg-MfqRIz15fboL8IuH .node path{fill:#fff4dd;stroke:hsl(40.5882352941, 60%, 83.3333333333%);stroke-width:1px;}#mermaid-svg-MfqRIz15fboL8IuH .rough-node .label text,#mermaid-svg-MfqRIz15fboL8IuH .node .label text,#mermaid-svg-MfqRIz15fboL8IuH .image-shape .label,#mermaid-svg-MfqRIz15fboL8IuH .icon-shape .label{text-anchor:middle;}#mermaid-svg-MfqRIz15fboL8IuH .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-MfqRIz15fboL8IuH .rough-node .label,#mermaid-svg-MfqRIz15fboL8IuH .node .label,#mermaid-svg-MfqRIz15fboL8IuH .image-shape .label,#mermaid-svg-MfqRIz15fboL8IuH .icon-shape .label{text-align:center;}#mermaid-svg-MfqRIz15fboL8IuH .node.clickable{cursor:pointer;}#mermaid-svg-MfqRIz15fboL8IuH .root .anchor path{fill:#0b0b0b!important;stroke-width:0;stroke:#0b0b0b;}#mermaid-svg-MfqRIz15fboL8IuH .arrowheadPath{fill:#0b0b0b;}#mermaid-svg-MfqRIz15fboL8IuH .edgePath .path{stroke:#0b0b0b;stroke-width:2.0px;}#mermaid-svg-MfqRIz15fboL8IuH .flowchart-link{stroke:#0b0b0b;fill:none;}#mermaid-svg-MfqRIz15fboL8IuH .edgeLabel{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);text-align:center;}#mermaid-svg-MfqRIz15fboL8IuH .edgeLabel p{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-MfqRIz15fboL8IuH .edgeLabel rect{opacity:0.5;background-color:hsl(-79.4117647059, 100%, 93.3333333333%);fill:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-MfqRIz15fboL8IuH .labelBkg{background-color:rgba(243.9999999999, 220.9999999998, 255, 0.5);}#mermaid-svg-MfqRIz15fboL8IuH .cluster rect{fill:hsl(220.5882352941, 100%, 98.3333333333%);stroke:hsl(220.5882352941, 60%, 88.3333333333%);stroke-width:1px;}#mermaid-svg-MfqRIz15fboL8IuH .cluster text{fill:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-MfqRIz15fboL8IuH .cluster span{color:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-MfqRIz15fboL8IuH div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:Microsoft YaHei;font-size:12px;background:hsl(220.5882352941, 100%, 98.3333333333%);border:1px solid hsl(220.5882352941, 60%, 88.3333333333%);border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-MfqRIz15fboL8IuH .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-MfqRIz15fboL8IuH rect.text{fill:none;stroke-width:0;}#mermaid-svg-MfqRIz15fboL8IuH .icon-shape,#mermaid-svg-MfqRIz15fboL8IuH .image-shape{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);text-align:center;}#mermaid-svg-MfqRIz15fboL8IuH .icon-shape p,#mermaid-svg-MfqRIz15fboL8IuH .image-shape p{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);padding:2px;}#mermaid-svg-MfqRIz15fboL8IuH .icon-shape .label rect,#mermaid-svg-MfqRIz15fboL8IuH .image-shape .label rect{opacity:0.5;background-color:hsl(-79.4117647059, 100%, 93.3333333333%);fill:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-MfqRIz15fboL8IuH .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-MfqRIz15fboL8IuH .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-MfqRIz15fboL8IuH :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
是
否
消息到达 Queue。
消息持久化?
deliveryMode = 2
是 →
写入持久化存储。
消息索引 + 内容落盘。
同时保留内存副本加速投递。
否 → 只放内存。
Broker 重启即丢。
内存压力 / 积压增长?
是 → Paging。
消息按页(32MB)换出到磁盘。
内存只留索引。
否 → 内存投递,
最快路径。
Consumer 消费时
按页读回。
三个关键结论:
- "持久化消息"≠"每条都实时刷盘" ------持久化消息先写盘再进内存副本,但批量/异步落盘 ;Broker 断电仍可能丢最后几毫秒的消息(要绝对不丢必须 Publisher Confirm 等到落盘确认,10 篇);
- 积压时 Paging 会拖慢性能 ------消息换出磁盘再读回,吞吐骤降;惰性队列(Lazy Queue)直接写磁盘不进内存,百万积压也稳定(3.12+ 经典队列默认此行为);
- 内存水位保护 ------RabbitMQ 内存超阈值(默认物理内存 40%)会阻塞所有 Producer(flow control),防止 OOM 崩溃(11 篇调优)。
3.2 三种队列类型选型
| 维度 | 经典队列(Classic) | Quorum Queue | Stream |
|---|---|---|---|
| 存储 | 内存优先+磁盘 paging | WAL+Raft 复制,磁盘为主 | 追加日志(类 Kafka) |
| 高可用 | 靠镜像(已废弃) | Raft 多数派(内置) | 复制日志 |
| 消费模型 | 消费即删 | 消费即删 | 可重复消费(按 Offset) |
| 吞吐 | 万级 | 万级(多数派写入略低) | 十万级+ |
| 功能支持 | 全(TTL/DLX/优先级) | 大部分(DLX✅ 优先级❌) | 少(无 DLX/TTL) |
| 适用 | 常规业务(存量) | 高可靠业务(新集群首选) | 日志/事件溯源/流处理 |
一句话 :新集群业务队列直接上 Quorum Queue(Raft 不丢+免配镜像),日志流场景试 Stream,经典队列是存量兼容------镜像队列已废弃不要再上。
3.3 磁盘目录结构
text
/var/lib/rabbitmq/mnesia/rabbit@node1/
├── queues/
│ └── <vhost-hash>/
│ └── <queue-uuid>/
│ ├── 00000001.wal ← Quorum Queue 的 WAL(Raft 日志)
│ └── msg_store_durable/ ← 经典队列持久化消息存储
├── msg_stores/
│ └── vhosts/<vhost-hash>/msg_store_persistent/
│ ├── 0000000000000001.rdq ← 消息内容文件(按 16MB 分段)
│ └── msg_store_index.ets ← 消息索引(ETS 内存表)
└── rabbit_durable_exchange.ets ← Exchange/Binding 元数据(durable 的)
消息存储是 VHost 级共享的 (msg_store)------同一 VHost 所有队列的持久化消息存在一起(类似 RocketMQ 混写 CommitLog 的思想),队列里只存索引;小消息(<4KB 默认)直接内嵌索引里(embedding),省一次寻址。
四、集群架构:元数据与消息的分布
4.1 集群的默认行为
#mermaid-svg-e3GUFCFSSpNI2ifa{font-family:Microsoft YaHei;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-e3GUFCFSSpNI2ifa .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-e3GUFCFSSpNI2ifa .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-e3GUFCFSSpNI2ifa .error-icon{fill:hsl(220.5882352941, 100%, 98.3333333333%);}#mermaid-svg-e3GUFCFSSpNI2ifa .error-text{fill:rgb(8.5000000002, 5.7500000001, 0);stroke:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-e3GUFCFSSpNI2ifa .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-e3GUFCFSSpNI2ifa .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-e3GUFCFSSpNI2ifa .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-e3GUFCFSSpNI2ifa .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-e3GUFCFSSpNI2ifa .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-e3GUFCFSSpNI2ifa .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-e3GUFCFSSpNI2ifa .marker{fill:#0b0b0b;stroke:#0b0b0b;}#mermaid-svg-e3GUFCFSSpNI2ifa .marker.cross{stroke:#0b0b0b;}#mermaid-svg-e3GUFCFSSpNI2ifa svg{font-family:Microsoft YaHei;font-size:16px;}#mermaid-svg-e3GUFCFSSpNI2ifa p{margin:0;}#mermaid-svg-e3GUFCFSSpNI2ifa .label{font-family:Microsoft YaHei;color:#333;}#mermaid-svg-e3GUFCFSSpNI2ifa .cluster-label text{fill:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-e3GUFCFSSpNI2ifa .cluster-label span{color:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-e3GUFCFSSpNI2ifa .cluster-label span p{background-color:transparent;}#mermaid-svg-e3GUFCFSSpNI2ifa .label text,#mermaid-svg-e3GUFCFSSpNI2ifa span{fill:#333;color:#333;}#mermaid-svg-e3GUFCFSSpNI2ifa .node rect,#mermaid-svg-e3GUFCFSSpNI2ifa .node circle,#mermaid-svg-e3GUFCFSSpNI2ifa .node ellipse,#mermaid-svg-e3GUFCFSSpNI2ifa .node polygon,#mermaid-svg-e3GUFCFSSpNI2ifa .node path{fill:#fff4dd;stroke:hsl(40.5882352941, 60%, 83.3333333333%);stroke-width:1px;}#mermaid-svg-e3GUFCFSSpNI2ifa .rough-node .label text,#mermaid-svg-e3GUFCFSSpNI2ifa .node .label text,#mermaid-svg-e3GUFCFSSpNI2ifa .image-shape .label,#mermaid-svg-e3GUFCFSSpNI2ifa .icon-shape .label{text-anchor:middle;}#mermaid-svg-e3GUFCFSSpNI2ifa .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-e3GUFCFSSpNI2ifa .rough-node .label,#mermaid-svg-e3GUFCFSSpNI2ifa .node .label,#mermaid-svg-e3GUFCFSSpNI2ifa .image-shape .label,#mermaid-svg-e3GUFCFSSpNI2ifa .icon-shape .label{text-align:center;}#mermaid-svg-e3GUFCFSSpNI2ifa .node.clickable{cursor:pointer;}#mermaid-svg-e3GUFCFSSpNI2ifa .root .anchor path{fill:#0b0b0b!important;stroke-width:0;stroke:#0b0b0b;}#mermaid-svg-e3GUFCFSSpNI2ifa .arrowheadPath{fill:#0b0b0b;}#mermaid-svg-e3GUFCFSSpNI2ifa .edgePath .path{stroke:#0b0b0b;stroke-width:2.0px;}#mermaid-svg-e3GUFCFSSpNI2ifa .flowchart-link{stroke:#0b0b0b;fill:none;}#mermaid-svg-e3GUFCFSSpNI2ifa .edgeLabel{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);text-align:center;}#mermaid-svg-e3GUFCFSSpNI2ifa .edgeLabel p{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-e3GUFCFSSpNI2ifa .edgeLabel rect{opacity:0.5;background-color:hsl(-79.4117647059, 100%, 93.3333333333%);fill:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-e3GUFCFSSpNI2ifa .labelBkg{background-color:rgba(243.9999999999, 220.9999999998, 255, 0.5);}#mermaid-svg-e3GUFCFSSpNI2ifa .cluster rect{fill:hsl(220.5882352941, 100%, 98.3333333333%);stroke:hsl(220.5882352941, 60%, 88.3333333333%);stroke-width:1px;}#mermaid-svg-e3GUFCFSSpNI2ifa .cluster text{fill:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-e3GUFCFSSpNI2ifa .cluster span{color:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-e3GUFCFSSpNI2ifa div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:Microsoft YaHei;font-size:12px;background:hsl(220.5882352941, 100%, 98.3333333333%);border:1px solid hsl(220.5882352941, 60%, 88.3333333333%);border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-e3GUFCFSSpNI2ifa .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-e3GUFCFSSpNI2ifa rect.text{fill:none;stroke-width:0;}#mermaid-svg-e3GUFCFSSpNI2ifa .icon-shape,#mermaid-svg-e3GUFCFSSpNI2ifa .image-shape{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);text-align:center;}#mermaid-svg-e3GUFCFSSpNI2ifa .icon-shape p,#mermaid-svg-e3GUFCFSSpNI2ifa .image-shape p{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);padding:2px;}#mermaid-svg-e3GUFCFSSpNI2ifa .icon-shape .label rect,#mermaid-svg-e3GUFCFSSpNI2ifa .image-shape .label rect{opacity:0.5;background-color:hsl(-79.4117647059, 100%, 93.3333333333%);fill:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-e3GUFCFSSpNI2ifa .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-e3GUFCFSSpNI2ifa .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-e3GUFCFSSpNI2ifa :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} RabbitMQ 集群(3 节点)。
元数据全节点同步
Exchange/Queue/Binding/VHost 定义
用户/权限------所有节点都有全量。
消息内容默认不复制!
Queue 的消息只在'宿主节点'
其他节点收到该 Queue 的请求
→ 转发到宿主节点。
后果:宿主节点挂
Queue 不可用(未持久化消息丢)
→ 要高可用必须 Quorum/镜像。
关键认知 :RabbitMQ 集群 ≠ 高可用------集群解决的是"元数据共享+连接分散",消息复制要靠 Quorum Queue(或旧镜像队列,11 篇详解)。
4.2 磁盘节点与内存节点
| 节点类型 | 元数据存储 | 说明 |
|---|---|---|
| 磁盘节点(disc,默认) | 内存 + 磁盘 | 集群至少 1 个磁盘节点(元数据持久化) |
| 内存节点(ram) | 仅内存 | 性能略好,重启元数据靠其他节点恢复------现在意义不大,全用磁盘节点 |
4.3 客户端连接策略
text
① 直连多节点:客户端配置多个地址(host1:5672,host2:5672,host3:5672)
------连接失败自动试下一个(Spring AMQP 原生支持地址列表)
② 负载均衡:HAProxy/LVS 前置,客户端只连 VIP
------生产大集群推荐(连接管理集中,节点变更不动客户端)
③ 注意:连到非宿主节点的 Queue 请求会被"透明转发"------
跨节点转发有额外开销,Queue 宿主与 Consumer 所在节点一致最优
五、跑一遍:从启动到观察路由与存储
下面是可以直接照做的实操示例(Docker 单机 + rabbitmqadmin 管理命令行),每一步给出真实结果。
5.1 启动与声明拓扑
shell
# ① Docker 启动(带管理界面)
docker run -d --name rabbit -p 5672:5672 -p 15672:15672 \
rabbitmq:3.13-management
# 管理界面:http://localhost:15672(guest/guest)
# ② 声明拓扑:topic Exchange + 两个 Queue + 绑定
docker exec rabbit rabbitmqadmin declare exchange name=order-exchange type=topic durable=true
docker exec rabbit rabbitmqadmin declare queue name=order-create-queue durable=true
docker exec rabbit rabbitmqadmin declare queue name=order-all-queue durable=true
docker exec rabbit rabbitmqadmin declare binding source=order-exchange \
destination=order-create-queue routing_key="order.create"
docker exec rabbit rabbitmqadmin declare binding source=order-exchange \
destination=order-all-queue routing_key="order.*"
# ③ 查看绑定关系
docker exec rabbit rabbitmqadmin list bindings source_name destination_name routing_key
③ 的输出(两条 Binding 规则就位):
text
+----------------+----------------------+--------------+
| source_name | destination_name | routing_key |
+----------------+----------------------+--------------+
| order-exchange | order-create-queue | order.create |
| order-exchange | order-all-queue | order.* |
+----------------+----------------------+--------------+
5.2 发消息观察路由
shell
# ④ 发一条 Routing Key = order.create 的消息(持久化)
docker exec rabbit rabbitmqadmin publish exchange=order-exchange \
routing_key=order.create payload='{"orderId":1001,"action":"create"}' \
properties='{"delivery_mode":2}'
# 输出:Message published
# ⑤ 查看两个队列的消息数
docker exec rabbit rabbitmqadmin list queues name messages messages_ready
⑤ 的输出 (一条消息同时进了两个 Queue------topic 通配符路由的直观体现):
text
+--------------------+----------+----------------+
| name | messages | messages_ready |
+--------------------+----------+----------------+
| order-all-queue | 1 | 1 |
| order-create-queue | 1 | 1 |
+--------------------+----------+----------------+
5.3 消费与"消费即删"验证
shell
# ⑥ 从 order-create-queue 取一条消息(ack 后删除)
docker exec rabbit rabbitmqadmin get queue=order-create-queue ackmode=ack_requeue_false count=1
⑥ 的输出:
text
+--------------------+--------------+---------------+-----------------------------+
| routing_key | exchange | message_count | payload |
+--------------------+--------------+---------------+-----------------------------+
| order.create | order-exchange| 1 | {"orderId":1001,"action":"create"} |
+--------------------+--------------+---------------+-----------------------------+
# ⑦ 再查队列:order-create-queue 已空,order-all-queue 还有 1 条
docker exec rabbit rabbitmqadmin list queues name messages
# | order-all-queue | 1 |
# | order-create-queue | 0 | ← 消费即删!没有"回溯重放"
💡 对照理解 :⑤证明"一条消息进多个 Queue "(Kafka/RocketMQ 做不到,它们靠多 Consumer Group);⑦证明"消费即删 "------Queue 是真正的"队列"不是"日志",消息被 ack 后就删除,没有 Kafka 式的按 Offset 回溯重放能力(要重放只能靠 Producer 重发或死信重投)。这两个行为都源自 2.3 节的模型差异:RabbitMQ 把智能放在 Broker(路由+队列管理),代价是存储模型简单、吞吐受限。
六、总结
6.1 一张图回顾全文
#mermaid-svg-F39L0lEmR89w4DJK{font-family:Microsoft YaHei;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-F39L0lEmR89w4DJK .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-F39L0lEmR89w4DJK .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-F39L0lEmR89w4DJK .error-icon{fill:hsl(220.5882352941, 100%, 98.3333333333%);}#mermaid-svg-F39L0lEmR89w4DJK .error-text{fill:rgb(8.5000000002, 5.7500000001, 0);stroke:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-F39L0lEmR89w4DJK .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-F39L0lEmR89w4DJK .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-F39L0lEmR89w4DJK .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-F39L0lEmR89w4DJK .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-F39L0lEmR89w4DJK .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-F39L0lEmR89w4DJK .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-F39L0lEmR89w4DJK .marker{fill:#0b0b0b;stroke:#0b0b0b;}#mermaid-svg-F39L0lEmR89w4DJK .marker.cross{stroke:#0b0b0b;}#mermaid-svg-F39L0lEmR89w4DJK svg{font-family:Microsoft YaHei;font-size:16px;}#mermaid-svg-F39L0lEmR89w4DJK p{margin:0;}#mermaid-svg-F39L0lEmR89w4DJK .label{font-family:Microsoft YaHei;color:#333;}#mermaid-svg-F39L0lEmR89w4DJK .cluster-label text{fill:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-F39L0lEmR89w4DJK .cluster-label span{color:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-F39L0lEmR89w4DJK .cluster-label span p{background-color:transparent;}#mermaid-svg-F39L0lEmR89w4DJK .label text,#mermaid-svg-F39L0lEmR89w4DJK span{fill:#333;color:#333;}#mermaid-svg-F39L0lEmR89w4DJK .node rect,#mermaid-svg-F39L0lEmR89w4DJK .node circle,#mermaid-svg-F39L0lEmR89w4DJK .node ellipse,#mermaid-svg-F39L0lEmR89w4DJK .node polygon,#mermaid-svg-F39L0lEmR89w4DJK .node path{fill:#fff4dd;stroke:hsl(40.5882352941, 60%, 83.3333333333%);stroke-width:1px;}#mermaid-svg-F39L0lEmR89w4DJK .rough-node .label text,#mermaid-svg-F39L0lEmR89w4DJK .node .label text,#mermaid-svg-F39L0lEmR89w4DJK .image-shape .label,#mermaid-svg-F39L0lEmR89w4DJK .icon-shape .label{text-anchor:middle;}#mermaid-svg-F39L0lEmR89w4DJK .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-F39L0lEmR89w4DJK .rough-node .label,#mermaid-svg-F39L0lEmR89w4DJK .node .label,#mermaid-svg-F39L0lEmR89w4DJK .image-shape .label,#mermaid-svg-F39L0lEmR89w4DJK .icon-shape .label{text-align:center;}#mermaid-svg-F39L0lEmR89w4DJK .node.clickable{cursor:pointer;}#mermaid-svg-F39L0lEmR89w4DJK .root .anchor path{fill:#0b0b0b!important;stroke-width:0;stroke:#0b0b0b;}#mermaid-svg-F39L0lEmR89w4DJK .arrowheadPath{fill:#0b0b0b;}#mermaid-svg-F39L0lEmR89w4DJK .edgePath .path{stroke:#0b0b0b;stroke-width:2.0px;}#mermaid-svg-F39L0lEmR89w4DJK .flowchart-link{stroke:#0b0b0b;fill:none;}#mermaid-svg-F39L0lEmR89w4DJK .edgeLabel{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);text-align:center;}#mermaid-svg-F39L0lEmR89w4DJK .edgeLabel p{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-F39L0lEmR89w4DJK .edgeLabel rect{opacity:0.5;background-color:hsl(-79.4117647059, 100%, 93.3333333333%);fill:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-F39L0lEmR89w4DJK .labelBkg{background-color:rgba(243.9999999999, 220.9999999998, 255, 0.5);}#mermaid-svg-F39L0lEmR89w4DJK .cluster rect{fill:hsl(220.5882352941, 100%, 98.3333333333%);stroke:hsl(220.5882352941, 60%, 88.3333333333%);stroke-width:1px;}#mermaid-svg-F39L0lEmR89w4DJK .cluster text{fill:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-F39L0lEmR89w4DJK .cluster span{color:rgb(8.5000000002, 5.7500000001, 0);}#mermaid-svg-F39L0lEmR89w4DJK div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:Microsoft YaHei;font-size:12px;background:hsl(220.5882352941, 100%, 98.3333333333%);border:1px solid hsl(220.5882352941, 60%, 88.3333333333%);border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-F39L0lEmR89w4DJK .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-F39L0lEmR89w4DJK rect.text{fill:none;stroke-width:0;}#mermaid-svg-F39L0lEmR89w4DJK .icon-shape,#mermaid-svg-F39L0lEmR89w4DJK .image-shape{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);text-align:center;}#mermaid-svg-F39L0lEmR89w4DJK .icon-shape p,#mermaid-svg-F39L0lEmR89w4DJK .image-shape p{background-color:hsl(-79.4117647059, 100%, 93.3333333333%);padding:2px;}#mermaid-svg-F39L0lEmR89w4DJK .icon-shape .label rect,#mermaid-svg-F39L0lEmR89w4DJK .image-shape .label rect{opacity:0.5;background-color:hsl(-79.4117647059, 100%, 93.3333333333%);fill:hsl(-79.4117647059, 100%, 93.3333333333%);}#mermaid-svg-F39L0lEmR89w4DJK .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-F39L0lEmR89w4DJK .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-F39L0lEmR89w4DJK :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} RabbitMQ 架构与存储。
路由模型。
Producer → Exchange → Binding
→ Queue → Consumer。
Exchange 只路由不存储。
一条消息可进多个 Queue。
路由不到默认丢弃
(mandatory / AE 兜底)。
VHost 隔离,Channel 多路复用。
存储机制。
经典队列:内存优先 + paging 换出。
持久化 ≠ 实时刷盘
(confirm 才保不丢)。
惰性队列:直接写磁盘抗积压。
msg_store VHost 级共享
(类 CommitLog)。
队列类型。
Classic:存量兼容。
Quorum:Raft 多数派,新集群首选。
Stream:日志型可回溯,流场景。
集群。
元数据全节点同步。
消息默认不复制!
集群 ≠ 高可用。
Quorum / 镜像才有消息冗余。
6.2 核心要点浓缩(十二条)
- RabbitMQ 定位 :路由最灵活的 MQ------Exchange+Binding 组合路由,AMQP 开放协议多语言友好;吞吐万级,适合中小规模+复杂路由。
- 核心模型 :Producer→Exchange→Binding→Queue→Consumer------Producer 不直接发 Queue,Exchange 是路由器(不存消息),Queue 是缓冲区(存消息)。
- 一条消息多 Queue :fanout/topic 下一条消息匹配多个 Binding 复制到多个 Queue------Kafka/RocketMQ 靠多 Consumer Group 实现类似效果。
- 路由不到默认丢弃 :要
mandatory=true退回 Producer 或配备用交换机(AE)兜底------上线前必测"路由不到的消息去哪了"。 - Connection/Channel :一个 TCP Connection 多路复用多个 Channel------Channel 非线程安全,每线程一个。
- 智能 Broker vs 哑 Broker :RabbitMQ 路由逻辑在 Broker(灵活但吞吐受限),Kafka 逻辑下放两端(薄 Broker 高吞吐)------模型差异决定所有行为差异。
- 经典队列存储 :内存优先,持久化消息落盘+内存副本,积压时 paging 换出------"持久化"≠"实时刷盘",断电仍可能丢最后几毫秒(要 Publisher Confirm)。
- 惰性队列 :消息直接写磁盘不进内存------百万级积压不撑爆内存(3.12+ 经典队列默认惰性)。
- msg_store 共享存储 :VHost 级消息集中存储、队列只存索引(小消息内嵌)------和 RocketMQ 混写 CommitLog 同款思想。
- 三种队列类型 :Classic(存量)、Quorum(Raft 多数派,新集群首选) 、Stream(日志型可回溯)------镜像队列已废弃。
- 集群 ≠ 高可用 :元数据全节点同步,消息内容默认只在宿主节点------要高可用必须 Quorum/镜像队列。
- 连接策略 :客户端配多地址自动切换,或 HAProxy 前置------Queue 宿主与 Consumer 同节点最优(跨节点转发有开销)。
📌 最后一句话 :RabbitMQ 的设计哲学是"路由与存储分离 "------Exchange 只管路由(不存消息),Queue 只管存储(不管路由),Binding 是两者的契约。这种分离让路由规则可以任意组合(一条消息进多个 Queue、按模式匹配、按属性分发),灵活性的代价是吞吐不如 Kafka/RocketMQ。理解了"智能 Broker"的模型,下一篇的确认机制、TTL/DLX/延迟队列就都是"在这个模型上长出来的特性"。
📌 配套阅读:
如果这篇文章对你有帮助,欢迎点赞、收藏、关注!