跳到主要内容
版本:4.0

联合队列

概述

本指南涵盖联合队列,它是 联合插件 提供的功能的一部分。

本指南中包含以下主题

还提供了单独的 联合插件参考 指南。

除了 联合交换 之外,RabbitMQ 还支持联合队列。此功能提供了一种在节点或集群之间平衡单个逻辑队列负载的方法。它通过将消息移动到其他联合对等体(节点或集群)来实现,当本地队列没有消费者时就会执行此操作。

联合交换将消息流从上游复制到一个或多个下游,而联合队列将数据移动到消费者所在的位置,始终优先考虑本地消费者而不是远程消费者。联合队列被认为是平等的对等体,它们之间没有像联合交换那样存在“领导者/跟随者”关系。

联合队列链接到其他联合对等体(称为上游队列)。它将从上游队列检索消息以满足来自本地消费者的消息需求。上游队列不需要重新配置。假定它们位于单独的节点或单独的集群中。

上游定义是一个 URI,它包含某些已知的查询参数,这些参数控制链接连接参数。可以使用 CLI 工具 或 HTTP API 通过 额外的插件 管理上游。

以下图表展示了两个 RabbitMQ 节点中的多个联合队列和非联合队列,这些节点使用队列联合进行连接

Overview of federated queues

使用队列联合时,通常只有集群中的一部分队列是联合的。某些队列本质上是特定“站点”(集群)及其用途的本地队列。

用例

典型的用例是在多个代理上拥有相同的“逻辑”队列。每个代理都会声明一个与所有其他联合队列上游的联合队列。这些链接将形成联合对等体(节点或集群)上的完整双向图。

这种逻辑分布式队列能够比单个队列具有更高的容量。当存在一定程度的局部性时,它将表现最佳;即尽可能多的消息从发布到它们的同一队列中进行消费,而联合机制只需要移动消息以执行负载平衡。

运行不同版本的 RabbitMQ 的代理可以使用联合进行连接。

限制

与非联合对等体和联合交换相比,联合队列包含一些限制或差异。

队列联合不会将 绑定 从下游传播到上游。

使用 basic.get(通过轮询进行消费,这是强烈不推荐的做法)的应用程序,如果本地队列(客户端连接到的节点上的队列)中没有消息,则无法通过联合检索消息。由于 basic.get 是同步方法,因此提供请求的节点必须阻塞,同时联系所有其他节点以检索更多消息。这与联合的可获得性和以分区容错为导向的设计和用例不符。

使用和配置

联合队列与任何其他队列的声明方式相同,由应用程序声明。为了使 RabbitMQ 识别需要联合的队列,以及应该从哪些节点消费消息,下游(消费)节点需要进行配置。

Federated queue policies

联合配置使用 运行时参数和策略,这意味着它可以在系统拓扑更改时动态配置和重新配置。配置涉及两个关键部分

  • 上游:这些是联合系统中的远程端点
  • 联合策略:这些控制哪些队列是联合的,以及它们将连接到哪些上游(对等体)

这两者都配置在下游节点或集群上。

要添加上游,请使用 rabbitmqctl set_parameter 命令。它接受三个参数

  • 参数类型,federation-upstream
  • 联合策略将引用的上游名称
  • 上游定义 JSON 文档,其中至少包含一个必填键 uri

以下示例配置了一个名为“origin”的上游,可以通过 remote-host.local:5672 联系到它

# Adds a federation upstream named "origin"
rabbitmqctl set_parameter federation-upstream origin '{"uri":"amqp://remote-host.local:5672"}'

指定上游后,可以添加控制联合的策略。它与添加任何其他 策略 的方式相同,使用 rabbitmqctl set_policy

# Adds a policy named "queue-federation"
rabbitmqctl 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 也存在消费者。

可以将联合队列绑定到联合交换。但是,结果可能与某些人预期的不同。由于联合交换将从其上游检索与其绑定匹配的消息,因此发布到联合交换的任何消息都将复制到与绑定匹配的任何节点。然后,联合队列将在节点之间移动这些消息,因此可能会在同一个节点上出现同一消息的多个副本。

© 2024 RabbitMQ. All rights reserved.