联邦队列
概述
本指南涵盖联合队列,它是 Federation 插件所提供功能的一个子集。
涵盖的主题包括
另有一份独立的Federation 插件参考指南可供查阅。
除联合交换机外,RabbitMQ 还支持联合队列。该功能提供了一种在节点或集群间平衡单个逻辑队列负载的方法。当本地队列没有消费者时,它会将消息移动到其他联合对等点(节点或集群)。
联合交换机将消息流从上游复制到一个或多个下游,而联合队列则将数据移动到消费者所在的位置,并始终优先使用本地消费者而非远程消费者。联合队列被视为平等的对等点,它们之间不存在像联合交换机那样的“领导者/跟随者”关系。
联合队列会链接到其他联合对等点(称为上游队列)。为了满足本地消费者的消息需求,它会从上游队列获取消息。上游队列无需重新配置。它们被假定位于单独的节点或集群中。
上游定义是一个包含特定识别查询参数的 URI,用于控制链接连接参数。可以使用命令行工具或通过附加插件提供的 HTTP API 来管理上游。
下图展示了两个通过队列联合连接的 RabbitMQ 节点中的几个联合队列和非联合队列。

使用队列联合时,通常只有集群中的一部分队列是联合的。某些队列可能本质上仅属于本地“站点”(集群)及其用途。
用例
典型的用法是将同一个“逻辑”队列分布在多个代理(Broker)上。每个代理声明一个将所有其他联合队列作为上游的联合队列。这些链接将在联合对等点(节点或集群)上形成一个完整的双向图。
这样一个逻辑分布队列的容量可以远高于单个队列。当存在一定程度的局部性时,其性能最佳;即尽可能从消息发布到的同一队列中消费,而联合机制仅在需要执行负载均衡时才移动消息。
运行不同 RabbitMQ 版本的代理可以使用联合进行连接。
队列联合也是蓝绿部署的重要组成部分,例如从 RabbitMQ 3.x 迁移到 4.x。
队列联合与 Shovel 有什么不同?
队列联合将消息从上游集群的源队列移动到本地(下游)集群的目标队列。这确实与 Shovel 的功能非常相似,但有几个关键区别:
| 特性 | Shovel | 队列联合 |
|---|---|---|
| 消息移动 | 无条件移动消息 | 仅当上游没有本地消费者时才移动消息 |
| 方向性 | 通常是单向的 | 可以是双向的,也可以是在多个集群间进行 N 向连接 |
限制
与非联合对等点以及联合交换机相比,联合队列包含一些限制或差异。
队列联合不会将绑定 (bindings) 从下游传播到上游。
使用 basic.get(通过轮询消费,一种极不推荐的做法)的应用程序,如果本地队列(客户端连接到的节点)中没有消息,则无法通过联合机制获取消息。由于 basic.get 是同步方法,服务请求的节点在联系所有其他节点以获取更多消息时必须阻塞。这与联合机制的可用性和分区容错设计原则及使用场景不符。
使用与配置
联合队列像其他任何队列一样由应用程序声明。为了让 RabbitMQ 识别某个队列需要联合,以及应该从哪些其他节点消费消息,需要配置下游(消费)节点。

联合配置使用运行时参数和策略,这意味着它可以在系统拓扑发生变化时动态进行配置和重配置。涉及两个关键配置部分:
- 上游:联合系统中的远程端点
- 联合策略:控制哪些队列被联合,以及它们将连接到哪些上游(对等点)
这两者都在下游节点或集群上配置。
要添加上游,请使用 rabbitmqctl set_parameter 命令。它接受三个参数:
- 参数类型,
federation-upstream - 联合策略将引用的上游名称
- 包含至少一个强制键
uri的上游定义 JSON 文档
以下示例配置了一个名为 "origin" 的上游,可以通过 remote-host.local:5672 进行连接
- 使用 rabbitmqctl (bash)
- 使用 rabbitmqadmin (bash)
- 使用 rabbitmqctl (PowerShell)
- 使用 PowerShell 的 rabbitmqadmin.exe
# Adds a federation upstream named "origin"
rabbitmqctl set_parameter federation-upstream origin '{"uri":"amqp://remote-host.local:5672"}'
# Adds a federation upstream named "origin"
rabbitmqadmin federation declare_upstream_for_queues --name origin \
--uri "amqp://remote-host.local:5672"
# Adds a federation upstream named "origin"
rabbitmqctl.bat set_parameter federation-upstream origin '"{""uri"":""amqp://remote-host.local:5672""}"'
# Adds a federation upstream named "origin"
rabbitmqadmin.exe federation declare_upstream_for_queues --name origin ^
--uri "amqp://remote-host.local:5672"
一旦指定了上游,就可以添加控制联合的策略。它像其他任何策略一样,使用 rabbitmqctl set_policy 进行添加。
- 使用 rabbitmqctl (bash)
- 使用 rabbitmqadmin (bash)
- 使用 rabbitmqctl (PowerShell)
- 使用 PowerShell 的 rabbitmqadmin.exe
# Adds a policy named "queue-federation"
rabbitmqctl set_policy queue-federation "^federated\." \
'{"federation-upstream-set":"all"}' \
--priority 10 \
--apply-to queues
# Adds a policy named "queue-federation"
rabbitmqadmin policies declare \
--name "queue-federation" \
--pattern "^federated\." \
--definition '{"federation-upstream-set":"all"}' \
--priority 10 \
--apply-to "queues"
# Adds a policy named "queue-federation"
rabbitmqctl.bat set_policy queue-federation '^federated\.' `
'"{""federation-upstream-set"":""all""}"' `
--priority 10 `
--apply-to queues
# Adds a policy named "queue-federation"
rabbitmqadmin.exe policies declare ^
--name "queue-federation" ^
--pattern "^federated\." ^
--definition "{""federation-upstream-set"":""all""}" ^
--priority 10 ^
--apply-to "queues"
在上面的示例中,该策略将匹配默认虚拟主机中名称以 federated. 为前缀的队列。这些队列将为所有已声明的上游设置联合链接。该策略的名称为 queue-federation。与任何策略一样,如果多个策略匹配同一个队列,将使用优先级最高的策略。即使优先级相同,多个策略定义也不会合并。
配置完成后,将为每个匹配的队列和上游对打开一个联合链接(连接)。这里的“匹配队列”是指被联合策略模式匹配的队列。如果没有队列匹配,则不会启动任何链接。
要取消匹配队列的联合,请使用策略名称删除该策略。
rabbitmqctl clear_policy queue-federation
复杂拓扑与循环处理
一个联合队列可以作为另一个联合队列的“上游”。甚至可以形成“循环”,例如,队列 A 声明队列 B 为其上游,而队列 B 声明队列 A 为其上游。允许更复杂的多连接布置。然而,此类复杂拓扑将变得越来越难以推理和排查。
与联合交换机不同,队列联合不会复制数据,也不会显式处理循环。消息在联合队列之间转发的次数没有限制。
在一组相互联合的队列中,消息会移动到有空闲消费能力的地方,因此如果空闲消费能力一直在移动,消息也会随之移动。由于消息仅在没有本地消费者时才移动到远程节点,因此消息在所有节点间移动并“循环”的情况很少见。
实现
联合队列将使用 AMQP 0-9-1(可选使用 TLS 加密)连接到其所有的上游队列。
联合队列仅在本地消息耗尽、有消费者需要消息,且上游队列有未被消费的“多余”消息时才会获取消息。其目的是确保仅在需要时才在联合队列之间传输消息。这是通过消费者优先级实现的。
如果消息从一个队列转发到另一个队列,则仅对在节点间经历完全相同路径的消息保留消息顺序。在某些情况下,发布时相邻的消息可能会采取不同的路径到达同一个节点进行消费;因此,在存在队列联合的情况下,消息可能会被重新排序。
每个单独的队列分别应用其参数;例如,如果您在联合队列上设置了 x-max-length,则该队列的长度将受到限制(可能会在写满时丢弃消息),但与它联合的其他队列不会受到影响。特别注意,当使用队列级或消息级 TTL 时,消息在传输到另一个队列时会重置其计时器。
陷阱
目前,联合队列无法仅基于某处对消息的需求,使消息在代理之间跨越多个跳数(hops)。例如,如果您在节点 A、B 和 C 上联合队列,A 与 B 连接,B 与 C 连接,但 A 和 C 不连接,那么如果 A 处有可用消息,而 C 处有等待的消费者,除非 B 处也有消费者,否则消息不会通过 B 从 A 传输到 C。
可以将联合队列绑定到联合交换机。然而,结果可能超出某些人的预期。由于联合交换机会从其上游检索匹配其绑定的消息,因此发布到联合交换机的任何消息都将被复制到所有匹配绑定的节点。随后,联合队列会在节点间移动这些消息,因此最终可能会在同一个节点上出现同一消息的多个副本。