[TOC] #### 1. 前言 --- 上一讲我们知道了普通集群的问题:队列数据只在一个节点上,节点挂了队列就不可用 你可能已经想到了:那把队列数据复制到其它节点上不就行了 ? 对,这就是镜像队列的思路 #### 2. 镜像队列 --- 镜像队列解决什么问题 ? 普通集群下: + 节点 A:order_queue(有数据) + 节点 B:order_queue(只有元数据) + 节点 C:order_queue(只有元数据) 节点 A 挂了,order_queue 就没了 镜像队列下: + 节点 A:order_queue(主节点,有数据) + 节点 B:order_queue(镜像,有数据) + 节点 C:order_queue(镜像,有数据) 节点 A 挂了,节点 B 或节点 C 自动接管,order_queue 继续提供服务 数据有了冗余,节点挂了队列还在,这才是真正的高可用 生活中的例子: 普通集群就像你只在一个银行网点存了钱 那个网点倒闭了,你的钱就没了(当然现实中银行不会这样) 镜像队列就像你把钱同时存在三个网点,任何一个网点倒闭了,另外两个网点还有你的钱 #### 3. 镜像队列怎么工作 --- 镜像队列有一个主节点(Master)和多个镜像节点(Mirror) + 所有消息的读写都走主节点 + 主节点把数据同步到镜像节点 + 主节点挂了,镜像节点自动升级为新的主节点 ```plaintext Producer → 节点 A(Master) → 消息写入 ↓ 同步 节点 B(Mirror) → 数据备份 节点 C(Mirror) → 数据备份 ``` Consumer 也是从主节点取消息 如果主节点挂了,RabbitMQ 自动从镜像节点里选一个当新的主节点 整个过程对 Producer 和 Consumer 来说是透明的,它们不需要改代码 #### 4. 怎么配置 --- 通过策略(Policy)来配置 你可以指定哪些队列需要镜像,镜像几份 ```bash # 进入容器 docker exec -it rabbitmq bash # 设置策略:所有队列镜像到所有节点 rabbitmqctl set_policy ha-all ".*" '{"ha-mode":"all"}' --apply-to queues ``` `ha-mode` 有几种选择: | 模式 | 含义 | | ------------ | ------------ | | all | 镜像到所有节点 | | exactly | 镜像到指定数量的节点 | | nodes | 镜像到指定名称的节点 | 一般生产环境用 `all` 或者 `exactly` 配合节点数量 #### 5. 镜像队列有什么问题 --- 镜像队列能用,也用了好多年,但它有一些设计上的问题: + 性能开销:每条消息都要同步到所有镜像节点,网络和磁盘开销不小,节点越多,同步越慢 + 主节点是瓶颈:所有读写都走主节点,主节点的压力很大,镜像节点只是「备份」,平时不参与读写 + 故障转移不够可靠:主节点挂了,镜像升级为主节点,但如果消息还没来得及同步到镜像,这部分消息就丢了 + 集群状态不一致的风险:网络分区(脑裂)的情况下,可能出现多个节点都认为自己是主节点,这就是 RabbitMQ 集群里最让人头疼的问题之一 为什么 RabbitMQ 后来不推荐镜像队列了 ? 正是因为上面这些问题 RabbitMQ 官方在 3.8 版本推出了一个新的队列类型:Quorum Queue(仲裁队列),专门用来替代镜像队列 下一讲我们来聊 #### 6. 本文小结 --- 镜像队列的核心:把队列数据复制到多个节点上,实现高可用 + 主节点负责读写,镜像节点负责备份 + 主节点挂了,镜像节点自动接管 + 通过 Policy 配置 但镜像队列有性能、可靠性、一致性方面的局限 下一讲我们来看 RabbitMQ 官方推荐的替代方案:Quorum Queue