联合队列
概述
本指南涵盖联合队列,它是 联合插件 提供的功能的一部分。
本指南中包含以下主题
还提供了单独的 联合插件参考 指南。
除了 联合交换 之外,RabbitMQ 还支持联合队列。此功能提供了一种在节点或集群之间平衡单个逻辑队列负载的方法。它通过将消息移动到其他联合对等体(节点或集群)来实现,当本地队列没有消费者时就会执行此操作。
联合交换将消息流从上游复制到一个或多个下游,而联合队列将数据移动到消费者所在的位置,始终优先考虑本地消费者而不是远程消费者。联合队列被认为是平等的对等体,它们之间没有像联合交换那样存在“领导者/跟随者”关系。
联合队列链接到其他联合对等体(称为上游队列)。它将从上游队列检索消息以满足来自本地消费者的消息需求。上游队列不需要重新配置。假定它们位于单独的节点或单独的集群中。
上游定义是一个 URI,它包含某些已知的查询参数,这些参数控制链接连接参数。可以使用 CLI 工具 或 HTTP API 通过 额外的插件 管理上游。
以下图表展示了两个 RabbitMQ 节点中的多个联合队列和非联合队列,这些节点使用队列联合进行连接
使用队列联合时,通常只有集群中的一部分队列是联合的。某些队列本质上是特定“站点”(集群)及其用途的本地队列。
用例
典型的用例是在多个代理上拥有相同的“逻辑”队列。每个代理都会声明一个与所有其他联合队列上游的联合队列。这些链接将形成联合对等体(节点或集群)上的完整双向图。
这种逻辑分布式队列能够比单个队列具有更高的容量。当存在一定程度的局部性时,它将表现最佳;即尽可能多的消息从发布到它们的同一队列中进行消费,而联合机制只需要移动消息以执行负载平衡。
运行不同版本的 RabbitMQ 的代理可以使用联合进行连接。
限制
与非联合对等体和联合交换相比,联合队列包含一些限制或差异。
队列联合不会将 绑定 从下游传播到上游。
使用 basic.get
(通过轮询进行消费,这是强烈不推荐的做法)的应用程序,如果本地队列(客户端连接到的节点上的队列)中没有消息,则无法通过联合检索消息。由于 basic.get
是同步方法,因此提供请求的节点必须阻塞,同时联系所有其他节点以检索更多消息。这与联合的可获得性和以分区容错为导向的设计和用例不符。
使用和配置
联合队列与任何其他队列的声明方式相同,由应用程序声明。为了使 RabbitMQ 识别需要联合的队列,以及应该从哪些节点消费消息,下游(消费)节点需要进行配置。
联合配置使用 运行时参数和策略,这意味着它可以在系统拓扑更改时动态配置和重新配置。配置涉及两个关键部分
- 上游:这些是联合系统中的远程端点
- 联合策略:这些控制哪些队列是联合的,以及它们将连接到哪些上游(对等体)
这两者都配置在下游节点或集群上。
要添加上游,请使用 rabbitmqctl set_parameter
命令。它接受三个参数
- 参数类型,
federation-upstream
- 联合策略将引用的上游名称
- 上游定义 JSON 文档,其中至少包含一个必填键
uri
以下示例配置了一个名为“origin”的上游,可以通过 remote-host.local:5672
联系到它
- bash
- PowerShell
# Adds a federation upstream named "origin"
rabbitmqctl set_parameter federation-upstream 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""}"'
指定上游后,可以添加控制联合的策略。它与添加任何其他 策略 的方式相同,使用 rabbitmqctl set_policy
- bash
- PowerShell
# 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"
rabbitmqctl.bat set_policy queue-federation '^federated\.' `
'"{""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 时,消息将在传输到另一个队列时重置其计时器。
陷阱
联合队列当前无法仅根据某个地方对消息的需求,导致消息在代理之间进行多次跳转。例如,如果在节点 A、B 和 C 上联合队列,其中 A 和 B 连接,B 和 C 连接,但 A 和 C 不连接,那么如果消息在 A 处可用,而消费者在 C 处等待,则消息将不会从 A 通过 B 传输到 C,除非 B 也存在消费者。
可以将联合队列绑定到联合交换。但是,结果可能与某些人预期的不同。由于联合交换将从其上游检索与其绑定匹配的消息,因此发布到联合交换的任何消息都将复制到与绑定匹配的任何节点。然后,联合队列将在节点之间移动这些消息,因此可能会在同一个节点上出现同一消息的多个副本。