bigywater.tech
RabbitMQ · 18

集群:节点、元数据与队列所在节点

集群里到底哪些东西是所有节点共享的,哪些只在一个节点?队列放在哪个节点由谁决定?节点永久下线要做什么?少数派的节点能做什么、不能做什么?这篇起了一个真实的三节点集群一项项验证。

+0.036 ms
经典队列在 n1,客户端连别的节点发布 p50 比直连多出的延迟
9 → 3+3+3
全部从 n1 声明 9 个队列:client-local 全在 n1,balanced 均分到三个节点
20 s
三个节点只剩一个时声明新队列的等待——没有返回

元数据

实测 · 本机执行输出
  n1@localhost 上看到 exchange ['x.meta']、队列 ['q.meta@n1@localhost']
  n2@localhost 上看到 exchange ['x.meta']、队列 ['q.meta@n1@localhost']
  n3@localhost 上看到 exchange ['x.meta']、队列 ['q.meta@n1@localhost']
  feature flag khepri_db 的状态: [('khepri_db', 'enabled')]

用户、vhost、exchange、队列定义和绑定在每个节点上都有,4.3.6 的元数据存储是基于 Raft 的 Khepri。队列里的消息则只在队列所在的节点(经典队列)或副本节点(quorum / stream)。

多一跳

实测 · 本机执行输出
  连到队列所在的 n1: p50 0.086 ms,p99 0.158 ms
  连到 n2: p50 0.122 ms,p99 0.219 ms
  连到 n3: p50 0.122 ms,p99 0.218 ms

客户端可以连任意节点操作任意队列,不在队列所在节点时消息被转发,本机上 p50 从 0.086 ms 增加到 0.122 ms。

队列放哪里

实测 · 本机执行输出
  默认(client-local),每个节点上的客户端各声明 3 个,leader 的分布: {'n1@localhost': 3, 'n2@localhost': 3, 'n3@localhost': 3}
  其中 loc.1.* 是 n1 上的客户端声明的: n1@localhost, n1@localhost, n1@localhost
  全部从 n1 的客户端声明 9 个队列:policy queue-leader-locator=balanced → {'n1@localhost': 3, 'n3@localhost': 3, 'n2@localhost': 3};不设 policy(client-local)→ {'n1@localhost': 9}

默认 queue-leader-locator=client-local:放在声明它的客户端所连的节点;balanced 按节点现有队列数放置。队列都从同一个节点创建的应用要设成 balanced。

节点离开

实测 · 本机执行输出
  停掉 n3 之后:Disk Nodes ['n1@localhost', 'n2@localhost', 'n3@localhost'];Running Nodes ['n1@localhost', 'n2@localhost']
  $ rabbitmqctl forget_cluster_node n3@localhost
    Removing node n3@localhost from the cluster
  forget 之后:Disk Nodes ['n1@localhost', 'n2@localhost'];Running Nodes ['n1@localhost', 'n2@localhost']

停掉的节点仍是集群成员(Disk Nodes 里还在),永久下线要 rabbitmqctl forget_cluster_node。

cookie

实测 · 本机执行输出
  $ rabbitmqctl -n q18x@localhost join_cluster n1@localhost
    Clustering node q18x@localhost with n1@localhost
    13:09:53.619 [error] Feature flags: error while running:
    Feature flags:   rabbit_ff_controller:running_nodes[]
    Feature flags: on node `n1@localhost`:
    Feature flags:   exception error: {erpc,noconnection}
    Error:
    {:aborted_feature_flags_compat_check, {:error, {:erpc, :noconnection}}}

节点靠相同的 Erlang cookie 互相认证。cookie 不一致时 join_cluster 只报 noconnection,看不出是 cookie 的问题。

少数派

实测 · 本机执行输出
  往已有的 exchange / 队列发布一条(带 confirm): 成功(1 ms)
  声明新队列 q.new: 20 秒内没有返回(用时 20.0 s)

元数据变更需要多数派。三个节点只剩一个时,已有队列的发布照常,新建队列等不到返回。

分步演示

集群
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / RabbitMQ 4.3.6 / Erlang/OTP 28.5 / pika 1.4.4(Homebrew 与临时虚拟环境);所有节点都是本机自己起的 RabbitMQ 进程(127.0.0.1,端口 9500 以上,每个实验独立的数据目录与节点名,不连任何外部服务);命令输出来自真实的 rabbitmqctl 与管理 API,发布与消费用 pika 的真实连接;计时用 time.perf_counter,数字每次运行会有小幅抖动。集群是 3 个本机节点(各自的数据目录、端口、节点名 n1~n3,共享同一个 .erlang.cookie);延迟用同步 confirm 发布 3000 条取 p50 / p99,各连接 3 轮取中位数;cookie 不一致的节点是另一个 HOME 里写了不同 cookie 的新节点
    • 没有验证:真实多机网络下的转发延迟;网络分区(而不是节点被杀)下 Khepri 的表现(见第 19 篇);滚动升级;节点数为 5、7 时的多数派;vhost 的 default-queue-type;队列迁移(rebalance)命令;客户端负载均衡
    京ICP备2026067502号-1京公网安备11010502063487号