3. 集群基础模式:普通集群(Classic Cluster)的搭建、节点发现与元数据同步机制

普通集群(Classic Cluster)是 RabbitMQ 最基础的分布式部署形态。它通过将多个 Erlang 节点连接成一个逻辑集群,实现队列元数据、交换器、绑定关系、虚拟主机、用户权限等信息的全局共享。本章将深入讲解普通集群的搭建步骤、节点发现机制以及元数据同步的核心原理。

3.1 普通集群架构概览

在普通集群中,所有节点共享 逻辑集群名称 和 Erlang Cookie。集群内的每个节点都保存一份完整的元数据副本(包括交换器、绑定、虚拟主机、用户等),但队列的消息体只存储在声明该队列的节点上,其他节点仅持有该队列的元数据指针和路由信息。

RabbitMQ 普通集群架构 节点 A (rabbit@node1) 元数据副本(完整) 队列 Q1(主副本) 队列 Q2(元数据指针) 队列 Q3(元数据指针) 消息体存储于此 节点 B (rabbit@node2) 元数据副本(完整) 队列 Q1(元数据指针) 队列 Q2(主副本) 队列 Q3(元数据指针) 消息体存储于此 节点 C (rabbit@node3) 元数据副本(完整) 队列 Q1(元数据指针) 队列 Q2(元数据指针) 队列 Q3(主副本) 消息体存储于此 元数据同步层(Mnesia 分布式数据库) 生产者 消费者
关键理解: 普通集群中,元数据全量同步,消息体按需路由。消费者连接到非队列主节点时,该节点会通过内部 Erlang 通信将请求转发到队列所在节点,这称为内部路由转发。

3.2 普通集群搭建步骤

搭建普通集群需要准备至少两台主机(或容器),确保它们之间网络互通,且 Erlang Cookie 一致。以下是基于三节点集群的搭建流程:

3.2.1 前置条件

  • 主机名解析: 所有节点的主机名必须能够互相解析(推荐使用 /etc/hosts 或 DNS)。
  • Erlang Cookie 一致: 将主节点的 .erlang.cookie 文件(通常位于 /var/lib/rabbitmq/.erlang.cookie)复制到所有从节点,权限设为 400。
  • 端口开放: 确保 4369(EPMD)、5672(AMQP)、25672(Erlang 分布式端口)等端口可互通。

3.2.2 搭建步骤

步骤 操作 命令/说明
1 启动各节点 RabbitMQ 服务 systemctl start rabbitmq-server 或 rabbitmq-server -detached
2 停止应用(保留 Erlang 节点) rabbitmqctl stop_app
3 重置节点状态 rabbitmqctl reset(仅从节点执行)
4 加入集群 rabbitmqctl join_cluster rabbit@node1(从节点执行)
5 启动应用 rabbitmqctl start_app
6 验证集群状态 rabbitmqctl cluster_status
示例: 将 node2 和 node3 加入以 node1 为种子节点的集群:
# 在 node2 上执行
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster rabbit@node1
rabbitmqctl start_app

# 在 node3 上执行
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster rabbit@node1
rabbitmqctl start_app

# 在任意节点查看集群状态
rabbitmqctl cluster_status

3.3 节点发现机制

RabbitMQ 普通集群的节点发现主要依赖 Erlang 分布式协议 和 EPMD(Erlang Port Mapper Daemon)。节点发现过程分为两个阶段:

3.3.1 发现流程

  1. 种子节点连接: 执行 join_cluster 时,从节点通过 EPMD 查询种子节点的 Erlang 分布式端口(默认 25672)。
  2. 握手与认证: 双方交换 Erlang Cookie 进行身份验证。Cookie 一致则建立加密连接。
  3. Mnesia 同步: 新节点从种子节点拉取完整的元数据副本,并注册到集群成员列表。
  4. 心跳维护: 节点间通过 net_ticktime(默认 60 秒)发送心跳,检测节点存活状态。

3.3.2 节点发现参数

参数 默认值 说明
net_ticktime 60 节点心跳间隔(秒),影响故障检测速度
cluster_formation.peer_discovery_backend rabbit_peer_discovery_classic_config 节点发现后端,支持 DNS、AWS、K8s 等
cluster_formation.node_cleanup.interval 30 清理失联节点信息的间隔(秒)

3.4 元数据同步机制

普通集群的元数据同步基于 Erlang 的 Mnesia 分布式数据库。Mnesia 是一个实时、内存/磁盘混合的分布式 DBMS,RabbitMQ 利用它存储所有逻辑配置信息。

3.4.1 同步内容

  • 交换器(Exchange): 名称、类型、属性、绑定关系。
  • 队列(Queue): 名称、属性、绑定关系(不含消息体)。
  • 绑定(Binding): 交换器与队列的关联规则。
  • 虚拟主机(VHost): 隔离环境配置。
  • 用户与权限: 认证与授权信息。
  • 运行时参数: 策略(Policy)、参数(Parameter)等。

3.4.2 同步方式

同步类型 触发条件 行为描述
全量同步 节点加入集群 新节点从种子节点拉取所有 Mnesia 表数据
增量同步 元数据变更(创建/删除/修改) 变更节点通过 Mnesia 事务广播到所有在线节点
定期同步 节点重连或网络分区恢复 Mnesia 自动对比表版本,同步差异数据
重要限制: 普通集群不提供队列消息体的高可用。如果队列所在节点宕机,该队列的消息将丢失,直到节点恢复。需要消息高可用时,应使用镜像队列(Mirrored Queues)或 Quorum Queues。

3.5 集群管理与验证

3.5.1 常用管理命令

# 查看集群状态
rabbitmqctl cluster_status

# 查看集群节点列表
rabbitmqctl list_nodes

# 移除节点(需在目标节点执行)
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl start_app

# 强制移除失联节点(在存活节点执行)
rabbitmqctl forget_cluster_node rabbit@node3

3.5.2 验证集群功能

  1. 元数据同步验证: 在 node1 创建交换器 test.exchange,在 node2 和 node3 上通过 rabbitmqctl list_exchanges 确认可见。
  2. 路由转发验证: 在 node1 声明队列 test.queue,在 node2 上绑定并发送消息,确认消费者在 node3 上能正常消费。
  3. 故障转移验证: 停止 node1 的 RabbitMQ 服务,检查 node2 和 node3 的集群状态,确认节点被标记为 down。
生产建议: 普通集群至少部署 3 个节点,以应对单节点故障时的元数据可用性。同时,建议将 net_ticktime 调整为 10-30 秒,加快故障检测速度。

3.6 本章小结