07 - 集群与高可用架构
面试高频度:⭐⭐⭐⭐ 考查方式:架构设计题、故障恢复题
一、为什么需要集群?
1.1 单节点 RabbitMQ 的问题
单节点 RabbitMQ 有三个致命缺陷:
| 问题 | 后果 |
|---|---|
| 单点故障 | Broker 宕机 → 所有消息收发停止,业务系统瘫痪 |
| 容量上限 | 单节点的内存和 CPU 有极限,消息量增长到一定程度就撑不住了 |
| 维护停机 | 升级版本、修改配置都需要停机,影响业务可用性 |
集群的核心价值:通过多节点协作,消除单点故障,提升整体可用性和容量。
1.2 集群的本质:共享元数据 + 数据复制
RabbitMQ 集群中所有节点共享元数据(Exchange、Queue、Binding 的定义),但消息数据的复制策略取决于队列类型——这是三种集群模式的本质区别。
二、三种集群模式
2.1 普通集群(Non-HA)——只共享元数据
原理:集群中所有节点都能看到同一个 Exchange 和 Queue 的定义(元数据同步),但消息只存在于 Queue 所在的那个节点上。
Node 1 (Queue A 主节点) Node 2 Node 3
┌──────────┐ ┌──────────┐ ┌──────────┐
│Queue A ✓ │ │Queue A │ │Queue A │
│(有消息) │ │(只有元数据)│ │(只有元数据)│
└──────────┘ └──────────┘ └──────────┘消息路由过程:如果 Consumer 连接到 Node 2 但 Queue A 在 Node 1 上,Node 2 会通过集群内部通信从 Node 1 拉取消息再转发给 Consumer。这个转发过程增加了网络延迟。
致命缺陷:Node 1 宕机后,Queue A 的消息全部不可用——没有自动故障转移机制。所以普通集群不能用于生产环境。
2.2 镜像队列(Mirrored Queue)——全量复制(已废弃)
原理:在普通集群的基础上,通过 HA Policy 配置,让 Queue 的消息同步复制到其他节点。一个 Master 节点处理所有读写,多个 Slave 节点作为副本。
Node 1 (Master) Node 2 (Slave) Node 3 (Slave)
┌──────────┐ ┌──────────┐ ┌──────────┐
│Queue A ✓ │ ──同步──▶ │Queue A ✓ │ ──同步──▶│Queue A ✓ │
│(写入+ACK) │ │(副本) │ │(副本) │
└──────────┘ └──────────┘ └──────────┘
Master 宕机 → 最老的 Slave 自动提升为新 Master镜像队列的同步机制:消息到达 Master 后,Master 会将消息同步发送给所有 Slave,Slave 确认收到后,Master 才向 Producer 返回 ACK。消费时,Master 处理 ACK 并通知 Slave 删除对应消息。
镜像队列为什么被废弃? 三个根本缺陷:
| 缺陷 | 原因 | 后果 |
|---|---|---|
| 性能差 | 同步复制到所有节点,Slave 越多越慢 | 写入吞吐量随节点数反比下降 |
| 数据不一致 | ACK 状态的同步是异步的 | Master 宕机时,部分已消费但 ACK 未同步的消息会被新 Master 重新投递 |
| 故障转移不可靠 | "最老的 Slave 提升为 Master"的选举策略太简单 | 可能选出数据不完整的节点做 Master |
2.3 仲裁队列(Quorum Queue)——Raft 共识(3.8+ 推荐)
原理:基于 Raft 共识协议实现的分布式队列。每个仲裁队列有一个 Leader 和多个 Follower,消息写入时需要多数派确认才算成功。
Node 1 (Leader) Node 2 (Follower) Node 3 (Follower)
┌──────────┐ ┌──────────┐ ┌──────────┐
│Queue A ✓ │ ──Raft──▶ │Queue A ✓ │ ──Raft──▶│Queue A ✓ │
│(Leader) │ │(Follower) │ │(Follower) │
└──────────┘ └──────────┘ └──────────┘
写入规则:3 个节点中至少 2 个确认 → 写入成功
Leader 宕机 → 自动选举新 Leader(秒级)为什么 Raft 比镜像队列更可靠?
| 维度 | 镜像队列 | 仲裁队列(Raft) |
|---|---|---|
| 一致性模型 | 异步复制,最终一致 | 多数派写入,强一致 |
| 数据丢失风险 | Master 宕机可能丢已消费未同步 ACK 的数据 | 只要多数节点存活,数据不丢 |
| 故障转移 | "最老 Slave"策略,简单但不可靠 | Raft Leader 选举,有完整的日志一致性保证 |
| 运维复杂度 | HA Policy 配置复杂,参数多 | x-queue-type=quorum 一个参数搞定 |
仲裁队列的多数派写入:以 3 节点为例,一条消息写入时 Leader 把它发给 2 个 Follower,只要 3 个节点中任意 2 个确认写入成功,就返回 ACK 给 Producer。这意味着即使 1 个节点宕机,剩余 2 个节点仍然能正常工作。
仲裁队列的限制:不支持某些特性(如 priority queue、临时队列、某些 TTL 配置),但这些限制在生产场景中通常不重要。
三、集群的关键运维问题
3.1 网络分区(脑裂)
什么是网络分区? 集群中的节点因为网络故障被分成两个或多个互相不可达的分区。每个分区各自认为对方宕机了,可能各自选出新的 Leader,导致两个分区同时接受写入——数据出现不一致。
正常集群: Node 1 ←→ Node 2 ←→ Node 3
网络分区后: Node 1 + Node 2(分区 A) | Node 3(分区 B)
多数派,正常工作 | 少数派,应该暂停三种处理策略:
| 策略 | 行为 | 适用场景 |
|---|---|---|
ignore | 不处理,等网络恢复后人工介入 | 不推荐——数据可能不一致 |
pause_minority | 少数派分区自动暂停服务 | 3 节点推荐——少数派知道自己是少数,主动暂停 |
autoheal | 网络恢复后自动重启少数派节点 | 5+ 节点推荐 |
为什么 pause_minority 对 3 节点最合适? 3 节点集群最多容忍 1 个节点故障。当网络分区把集群分成 2+1 时,1 个节点的分区知道自己是少数派,主动暂停服务。2 个节点的分区继续正常工作。这样保证了整个集群只有一个"权威版本",不会出现脑裂。
3.2 负载均衡
集群前面通常加一层负载均衡器(HAProxy / Nginx),客户端通过负载均衡器连接到集群:
Client ──▶ HAProxy ──┬──▶ Node 1 (Leader)
├──▶ Node 2 (Follower)
└──▶ Node 3 (Follower)仲裁队列的优势:仲裁队列会自动将 Consumer 的连接路由到 Leader 节点,即使 Consumer 连接的是 Follower,消息也会从 Leader 获取。所以负载均衡器的策略不需要特别关心 Queue 的 Leader 位置。
3.3 节点类型
| 类型 | 说明 | 适用场景 |
|---|---|---|
| disc | 元数据存储到磁盘,Broker 重启后元数据不丢 | 生产必须——至少 2 个 disc 节点 |
| ram | 元数据只存内存,读写更快,但重启后元数据丢失 | 大规模集群中配合 disc 使用,提升元数据访问速度 |
四、集群最少需要几个节点?
| 队列类型 | 最少节点 | 推荐节点 | 容忍故障数 |
|---|---|---|---|
| 普通队列 | 2 | 3 | 0(无 HA) |
| 镜像队列 | 2 | 3 | 1(3 副本时) |
| 仲裁队列 | 3 | 3 或 5 | 1(3 节点)/ 2(5 节点) |
为什么仲裁队列最少要 3 个节点? Raft 协议要求多数派确认。2 个节点时多数派 = 2,即任何一个节点宕机就无法写入——和单点故障没有区别。3 个节点时多数派 = 2,容忍 1 个故障。
五、面试常见追问
Q1:仲裁队列和镜像队列怎么选?
3.8+ 一律选仲裁队列。镜像队列已被官方标记为 deprecated(废弃)。仲裁队列基于 Raft,强一致性、故障转移更快、运维更简单。如果你的项目还在用镜像队列,面试时可以说"计划迁移到 Quorum Queue"。
Q2:集群中的 Queue 存在于几个节点?
- 普通队列:只存在于 1 个节点
- 镜像队列:存在于所有节点(ha-mode=all)或指定数量节点
- 仲裁队列:存在于所有节点(默认),通过
x-quorum-initial-group-size可以指定副本数
Q3:如何实现零停机迁移?
1. 新集群搭建完成
2. Federation 插件:旧集群 → 新集群同步消息
3. 逐步切换 Producer 到新集群
4. Consumer 消费完旧集群消息后切换
5. 关闭 Federation,下线旧集群Federation 插件可以在两个集群之间建立消息同步通道,实现不停机迁移。
六、关联笔记
- **RabbitMQ基础与核心概念** - 集群基础概念
- **消息可靠性保障** - 与集群配合的可靠性方案
- **SpringBoot整合RabbitMQ** - 集群配置示例