4. 集群基础
RabbitMQ 集群通过 Erlang 分布式协议将多个节点连接成一个逻辑整体,实现队列元数据、交换器、绑定关系的全局复制,从而突破单节点瓶颈,提供更高的吞吐量与可用性。本章深入剖析集群核心原理,并给出可复现的搭建步骤。
4.1 Erlang 分布式基础
RabbitMQ 基于 Erlang/OTP 构建,其集群本质上是 Erlang 节点间的分布式连接。每个 RabbitMQ 进程对应一个 Erlang 节点(rabbit@hostname),节点间通过 Erlang 分布式协议(EPMD)通信。
| 概念 | 说明 |
|---|---|
| Erlang 节点 | 一个独立的 Erlang 虚拟机实例,拥有唯一名称 name@ip 或 name@host |
| EPMD | Erlang Port Mapper Daemon,默认端口 4369,负责节点发现与端口映射 |
| 分布式连接 | 节点间通过 TCP 长连接交换消息,默认使用 全连接拓扑(每个节点与集群内所有其他节点直连) |
| Cookie 认证 | 所有节点必须使用相同的 .erlang.cookie 文件,否则无法建立连接 |
关键约束:Erlang 分布式要求节点间主机名可解析(DNS 或 /etc/hosts),且防火墙开放 EPMD 端口(4369)及节点间通信端口(默认范围 35672–35682)。
4.2 Cookie 同步机制
.erlang.cookie 是 Erlang 节点的共享密钥,位于 $HOME/.erlang.cookie(Linux)或 C:\Users\%USERNAME%\.erlang.cookie(Windows)。集群内所有节点必须持有完全相同的 Cookie 内容。
- 生成时机:首次启动 RabbitMQ 时自动生成,随机 32 字符字符串。
- 同步方法:
- 从已运行节点复制 Cookie 文件到新节点。
- 使用
rabbitmqctl set_cluster_name或手动编辑文件。 - 重启 RabbitMQ 服务使新 Cookie 生效。
- 权限要求:Cookie 文件权限必须为
400(仅属主可读),否则 Erlang 虚拟机拒绝启动。
常见错误:Cookie 不一致时,节点日志出现
Connection attempt from disallowed node 或 authentication failed。务必在加入集群前校验所有节点的 Cookie 内容。
4.3 节点发现与集群形成
RabbitMQ 支持两种节点发现模式:手动发现(传统方式)和 自动发现(基于插件)。
| 发现方式 | 原理 | 适用场景 |
|---|---|---|
| 手动发现 | 使用 rabbitmqctl join_cluster 指定已有节点 |
小规模集群(≤5 节点)、静态环境 |
| DNS 发现 | 通过 DNS A/AAAA 记录解析集群节点列表 | 动态扩缩容、容器化部署 |
| Consul/Etcd 发现 | 依赖外部服务注册中心 | 大规模生产集群、跨机房部署 |
集群形成后,节点间通过 Mnesia 数据库(Erlang 内置分布式 DB)同步元数据:交换器、队列绑定、虚拟主机、权限等。但 队列消息体本身不会跨节点复制——这是 RabbitMQ 集群与镜像队列/仲裁队列的核心区别。
4.4 集群搭建步骤(手动方式)
以下步骤基于 CentOS 7 / Ubuntu 22.04,使用三台主机(node-a, node-b, node-c)构建 3 节点集群。
4.4.1 环境准备
- 主机名与解析:确保每台机器的主机名唯一,且
/etc/hosts包含所有节点 IP 映射。 - 防火墙:开放端口 4369(EPMD)和 35672–35682(节点间通信)。
- 安装 RabbitMQ:所有节点安装相同版本(推荐 3.12+)。
# 示例 /etc/hosts 配置(所有节点一致)
192.168.1.10 node-a
192.168.1.11 node-b
192.168.1.12 node-c
4.4.2 Cookie 同步
- 在 node-a 上查看 Cookie:
cat /var/lib/rabbitmq/.erlang.cookie - 将内容复制到 node-b 和 node-c 的相同路径。
- 设置权限:
chmod 400 /var/lib/rabbitmq/.erlang.cookie - 重启 RabbitMQ:
systemctl restart rabbitmq-server
4.4.3 启动并加入集群
- 启动所有节点的 RabbitMQ 服务。
- 在 node-b 上执行:
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster rabbit@node-a
rabbitmqctl start_app
- 在 node-c 上执行相同命令,目标节点仍为
rabbit@node-a。 - 在任意节点验证集群状态:
rabbitmqctl cluster_status
# 输出示例
Cluster status of node rabbit@node-a ...
Basics
Cluster name: rabbit@node-a
Disk Nodes
rabbit@node-a
rabbit@node-b
rabbit@node-c
Running Nodes
rabbit@node-a
rabbit@node-b
rabbit@node-c
4.4.4 设置集群名称(可选)
rabbitmqctl set_cluster_name "production-cluster-01"
4.5 集群验证与常用命令
| 命令 | 用途 |
|---|---|
rabbitmqctl cluster_status |
查看集群节点列表、运行状态、分区状态 |
rabbitmqctl list_connections |
查看客户端连接分布 |
rabbitmqctl list_queues |
查看队列及其所在节点 |
rabbitmq-diagnostics check_port_connectivity |
检测节点间端口连通性 |
rabbitmq-diagnostics erlang_cookie_sources |
检查 Cookie 来源与一致性 |
生产建议:集群节点数建议为奇数(3、5、7),配合仲裁队列实现多数派选举,避免脑裂。首次搭建完成后,务必测试节点宕机与恢复场景,验证集群自愈能力。
4.6 集群关键特性与限制
- 元数据全局复制:交换器、队列、绑定、用户、权限在所有节点一致。
- 消息体单节点存储:队列消息只存在于声明该队列的节点,其他节点通过内部转发路由。
- 客户端连接透明:生产者/消费者可连接任意节点,集群自动路由到目标节点。
- 网络分区风险:节点间网络中断会导致集群分裂,需配置分区处理策略(pause-minority / autoheal)。
- 节点类型:RAM 节点(元数据在内存)和 Disk 节点(元数据持久化),生产环境至少保留一个 Disk 节点。
核心结论:RabbitMQ 集群提供的是 元数据高可用,而非消息体高可用。要实现消息体跨节点冗余,必须使用镜像队列(经典版)或仲裁队列(现代推荐)。