bigywater.tech
RabbitMQ · 15

quorum 队列与经典镜像队列的区别

镜像队列(ha-mode)曾是 RabbitMQ 高可用的标配,quorum 队列取代了它。到了 4.3.6 镜像到底还剩什么?杀掉队列所在的节点,两种队列分别怎么表现?三副本写入的吞吐代价有多大?这篇起了一个真实的三节点集群来验证。

303 ms
kill -9 掉 quorum 队列 leader 所在节点后,到能带 confirm 继续发布的时间
66.6 s
经典队列所在节点被杀后,客户端访问该队列等到超时报 404 的时间
removed
4.3.6 里 classic_queue_mirroring 的废弃阶段,ha-mode 策略已被拒绝

集群里放什么

实测 · 本机执行输出
  Disk Nodes
    n1@localhost
    n2@localhost
    n3@localhost
  Running Nodes
    n1@localhost
    n2@localhost
    n3@localhost
  Versions
    n1@localhost: RabbitMQ 4.3.6 on Erlang 28.5.0.7
    n2@localhost: RabbitMQ 4.3.6 on Erlang 28.5.0.7
    n3@localhost: RabbitMQ 4.3.6 on Erlang 28.5.0.7

集群共享元数据(用户、vhost、exchange、队列定义、绑定),而经典队列的消息只存在它所在的节点。所以“节点挂了”对单副本的经典队列是实打实的不可用。

队列成员

实测 · 本机执行输出
  name	type	leader	members	online	messages
  cq	classic	n1@localhost	[n1@localhost]		1000
  qq	quorum	n1@localhost	[n1@localhost, n2@localhost, n3@localhost]	[n1@localhost, n2@localhost, n3@localhost]	0

rabbitmqctl list_queues name type leader members online 能看到每个队列的类型、leader、成员和在线成员:经典队列只有一个成员,quorum 队列默认每个节点一个副本。

镜像队列已移除

实测 · 本机执行输出
  $ rabbitmqctl set_policy ha-all "^cq$" '{"ha-mode":"all","ha-sync-mode":"automatic"}' --apply-to queues
    Error:
    Validation failed
    [{<<"ha-mode">>,<<"all">>},{<<"ha-sync-mode">>,<<"automatic">>}] are not recognised policy settings
  list_policies: Listing policies for vhost "/" ...
  策略生效后 cq 仍是: cq	classic	n1@localhost	[n1@localhost]
  classic_queue_mirroring 的状态: [('removed', 'denied')]
  broker 日志里关于镜像的行: (无)

在 4.3.6 里设置 ha-mode 策略直接被拒绝(not recognised policy settings),classic_queue_mirroring 的阶段是 removed。想要多副本就用 quorum 队列。

节点挂了

实测 · 本机执行输出
  quorum 队列 qq: 杀掉 n1 后第一次成功发布(带 confirm)在 303 ms 之后
  Listing queues for vhost / ...
  name	type	leader	members	online	messages
  qq	quorum	n2@localhost	[n2@localhost, n1@localhost, n3@localhost]	[n2@localhost, n3@localhost]	1000
  classic 队列 cq(它只在 n1 上,n1 已死): ChannelClosedByBroker: (404, "NOT_FOUND - failed to perform operation on queue 'cq' in vhost '/' due to timeout");这个调用等了 66.6 s 才失败
  从 n2 把 qq 取空:共 1001 条(1000 条原有 + 1 条 kill 之后发的)

杀掉 leader 所在的节点后,quorum 队列在 303 ms 内选出新 leader 继续服务,数据没丢;经典队列要等客户端超时(66.6 s)才报 404。

恢复

实测 · 本机执行输出
  name	type	leader	members	online	messages
  cq	classic	n1@localhost	[n1@localhost]		1000
  qq	quorum	n2@localhost	[n2@localhost, n1@localhost, n3@localhost]	[n2@localhost, n1@localhost, n3@localhost]	0
  从 cq 取一条: 'm0'(重启后 classic 队列的持久消息还在)

节点回来后经典队列的持久消息还在,quorum 队列的副本作为 follower 追上进度,leader 不会自动回到原来的节点。

复制的代价

实测 · 本机执行输出
  bench.classic     371 ms    53882 条/秒
  bench.quorum      372 ms    53750 条/秒

在本机回环上,三副本的 quorum 队列和单副本经典队列的发布吞吐几乎一样(53750 与 53882 条/秒)。真实网络、磁盘上的代价没有在这里测。

分步演示

quorum 与镜像
本步的对象

    本文用到的工具与边界

    • 本机 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、n2、n3,每个独立的数据目录与端口),节点通过 join_cluster 加入;kill -9 的恢复时间来自循环重连并带 confirm 发布的第一次成功;经典队列的超时是客户端 passive declare 等到的 404;吞吐是 pika SelectConnection 异步 confirm 发布 20000 条,3 轮取中位数
    • 没有验证:跨机器网络下的复制延迟;磁盘慢时 quorum 的吞吐;多于 3 个成员的 quorum 队列;节点被杀时在途消息的结果(只看了杀掉之后的第一次成功发布);退役 / 滚动升级;选举时间的分布(只测了一次 303 ms,没有多次统计)
    京ICP备2026067502号-1京公网安备11010502063487号