此功能提供了一种跨远程代理平衡单个队列负载的方法。

联合队列链接到其他队列(称为上游队列)。它将从上游队列检索消息以满足本地消费者对消息的需求。上游队列不需要重新配置,也不必位于同一代理或同一集群中。

建立上游链接和联合队列所需的所有配置都在下游代理中。

1. 使用场景

这不是对联合队列功能和优势的详尽列表,而只是一些想法。

  • 更高容量

    通过将“逻辑”队列分布在多个代理上。每个代理都会声明一个与所有其他联合队列处于上游的联合队列。(链接将在 n 个队列上形成一个完整的双向图。)

通过这种方式,一个逻辑分布式队列能够比单个代理上的单个队列具有更高的容量。当存在一定程度的局部性时,性能最佳。

例如,尽可能多的消息从与发布消息相同的代理消费,在这种情况下,联合只需要移动消息才能执行负载均衡。

federated queue symmetric
图 1. 联合队列对称
  • 支持多区域或场地

    在多区域设置中,你可能在一个区域或场地拥有生产者,而在另一个区域或场地拥有消费者。通常,你希望生产者和消费者保持与区域的本地连接,在这种情况下,你可以在生产者和消费者所在的每个区域部署代理,并使用联合在区域之间通过 WAN 移动消息。

federated queue
图 2. 联合队列
  • 安全企业 LAN 和 DMZ 之间的通信。

    当多个生产者应用程序可能位于 DMZ 中,而多个消费者应用程序位于安全企业 LAN 中时,允许生产者连接到安全企业 LAN 中的代理可能并不合适。

    在这种情况下,你可以在生产者发布的 DMZ 中部署一个代理,然后让企业 LAN 中的代理连接到 DMZ 代理并联合队列,以便消息可以传输。

    这类似于支持多区域或场地。

  • 在两个集群之间迁移。消费者和发布者可以按任何顺序移动,并且消息不会被复制(如果执行交换联合,则会出现这种情况)。相反,当你的消费者在那里时,消息将被传输到新集群。对于使用蓝绿或金丝雀迁移多个消费者到同一个队列,你可能希望将 `priority-adjustment` 设置为 0,甚至设置为正值,以便消息会主动流向联合队列。

  • 双重联合 - 消息在集群之间来回翻转的可能性。如果队列上的积压超过消费者可用的本地信用,任何低优先级联合消费者都将成为分派的候选者,并且消息将被联合。最终所有消息都可能迁移,并且这种情况可能会在另一个集群上重复。对连接器 URL 应用速率限制可以帮助缓解这种情况,但这可能会对没有本地消费者的迁移产生负面影响。为了更好地支持此用例,可以在引用的连接器 URI 上将 `consumerWindowSize` 配置为零:`tcp://<host>:<port>?consumerWindowSize=0`。这将导致联合消费者仅在本地队列有剩余容量时才批量拉取消息。这意味着联合永远不会消耗超过其处理能力的消息,因此消息不会来回翻转。批次大小是从相关的地址设置 `defaultConsumerWindowSize` 派生的。

2. 配置队列联合

联合在 `broker.xml` 文件中配置。

队列联合设置示例

<federations>
    <federation name="eu-north-1" user="federation_username" password="32a10275cf4ab4e9">
        <upstream name="eu-east-1">
           <static-connectors>
              <connector-ref>eu-east-connector1</connector-ref>
              <connector-ref>eu-east-connector2</connector-ref>
           </static-connectors>
           <policy ref="news-queue-federation"/>
        </upstream>
        <upstream name="eu-west-1" >
           <static-connectors>
              <connector-ref>eu-west-connector1</connector-ref>
              <connector-ref>eu-west-connector2</connector-ref>
           </static-connectors>
           <policy ref="news-queue-federation"/>
        </upstream>

        <queue-policy name="news-queue-federation" priority-adjustment="-5" include-federated="true" transformer-ref="news-transformer">
           <include queue-match="#" address-match="queue.bbc.new" />
           <include queue-match="#" address-match="queue.usatoday" />
           <include queue-match="#" address-match="queue.news.#" />

           <exclude queue-match="#.local" address-match="#" />
        </queue-policy>

        <transformer name="news-transformer">
           <class-name>org.foo.NewsTransformer</class-name>
           <property key="key1" value="value1"/>
           <property key="key2" value="value2"/>
        </transformer>
    </federation>
</federations>

在上面的设置中,下游代理 `eu-north-1` 配置为连接到两个上游代理 `eu-east-1` 和 `eu-west-1`,此示例中用于连接到两个代理的凭据是共享的,如果你需要为每个上游设置不同的用户和密码,你可以在上游级别设置。

两个上游都配置了相同的队列策略 `news-queue-federation`,该策略选择匹配任何包含条件的地址,但将排除以 `。local` 结尾的任何队列,将这些队列保留为本地队列。

重要的是联合名称在全局范围内是唯一的。

2.1. 优先级排序队列策略参数

名称

所有地址策略在服务器中必须具有唯一的名称。

包含

用于包含地址的地址匹配模式。可以设置多个此类模式。如果未设置任何模式,则将匹配所有地址。

排除

用于排除地址的地址匹配模式。可以设置多个此类模式。

优先级调整

当消费者附加时,使用其优先级来创建上游消费者,但默认情况下进行调整 -1,以便本地消费者优先于远程消费者进行负载均衡,这使得可以根据需要配置此选项。

包含联合

默认情况下,此值为 `false`,我们不会联合联合消费者,这是为了避免问题,在对称或任何闭环设置中,最终可能没有连接的“真实”消费者,并且消息会无休止地循环往复。

但是,如果你的设置不是闭环,例如,三个代理在链中(A->B->C),生产者在代理 A,消费者在 C,那么你可能希望代理 B 将消费者重新联合到 A 上。

转换器引用

你可能希望配置的转换器(见转换器配置)的引用名称,以便在联合传输时转换消息。

`address-policy` 和 `queue-policy` 元素能够在同一个联合中定义,并且它们可以链接到同一个上游。

2.2. 优先级排序转换器参数

名称

服务器中用于在 `address-policy` 和 `queue-policy` 中引用转换器的唯一名称。

转换器类名称

可以指定可选的 `transformer-class-name`。这是实现 `org.apache.activemq.artemis.core.server.transformer.Transformer` 接口的用户定义类的名称。

如果指定,则在消息被联合之前,将使用消息调用转换器的 `transform()` 方法。这让你有机会在消息被联合之前转换消息的标头或正文。

属性

保存可用于配置转换器的键值对。

2.3. 上游参数

标记 `upstream` 定义了上游代理连接和要使用的策略。

名称

上游联合服务器的唯一名称。

用户

此可选属性确定在创建到远程服务器的上游连接时要使用的用户名。如果未指定,则如果设置了共享联合用户和密码,则将使用它们。

密码

此可选属性确定在创建到远程服务器的上游连接时要使用的密码。如果未指定,则如果设置了共享联合用户和密码,则将使用它们。

静态连接器

使用此属性或 `discovery-group-ref` 来将桥接连接到目标服务器。

`static-connectors` 是 `connector-ref` 元素列表,这些元素指向在其他地方定义的 `connector` 元素。连接器封装了要使用的传输(TCP、SSL、HTTP 等)的知识以及服务器连接参数(主机、端口等)。

有关连接器是什么以及如何配置它们的更多信息,请参阅 配置传输

发现组引用

使用此属性或 `static-connectors` 来将桥接连接到目标服务器。

`discovery-group-ref` 元素只有一个属性 - `discovery-group-name`。此属性指向在其他地方定义的 `discovery-group`。有关发现组是什么以及如何配置它们的更多信息,请参阅 发现组

HA

此可选参数确定此桥接是否应该支持高可用性。`True` 表示它将连接到集群中的任何可用服务器并支持故障转移。默认值为 `false`。

断路器超时

当发生连接问题时,由于单个连接由多个联合队列和地址消费者共享,为了避免每个消费者都尝试重新连接,并可能导致“惊群”问题,将首先尝试第一个消费者。如果尝试失败,则断路器将打开,并将相同的异常返回到所有连接。这是断路器可以关闭并重新尝试连接之前的超时时间。以毫秒为单位测量。

共享连接

如果为同一个代理配置了下游和上游连接,那么只要两个流配置都将此标志设置为 true,就会共享同一个连接。默认值为 `false`。

检查周期

用于检查联合连接是否已无法从另一台服务器接收心跳的周期(以毫秒为单位)。默认值为 30000。

连接 TTL

如果联合连接停止从远程代理接收消息,则其应该保持活动的时间。默认值为 60000。

调用超时

当通过联合连接发送数据包时,这是一个阻塞调用,即用于确认,这是其在抛出异常之前等待回复的时间(以毫秒为单位)。默认值为 30000。

调用故障转移超时

与 `call-timeout` 类似,但在故障转移尝试期间进行调用时使用。默认值为 -1(无超时)。

重试间隔

此可选参数确定如果到目标服务器的连接失败,则后续重新连接尝试之间的周期(以毫秒为单位)。默认值为 500 毫秒。

重试间隔乘数

用于在每次重新连接尝试后增加 `retry-interval`,默认值为 1。

最大重试间隔

重试的最大延迟(以毫秒为单位)。默认值为 2000。

初始连接尝试次数

系统将尝试连接到联合中的远程代理的次数。如果达到 `max-retry`,则该代理将被视为永久性关闭,并且系统将不会将消息路由到该代理。默认值为 -1(无限重试)。

重新连接尝试次数

系统将尝试重新连接到联合中的远程代理的次数。如果达到 `max-retry`,则该代理将被视为永久性关闭,并且系统将停止将消息路由到该代理。默认值为 -1(无限重试)。

3. 配置下游联合

与 `upstream` 配置类似,可以配置 `downstream` 配置。这是通过向 `downstream` 代理发送命令使其创建回下游代理的 `upstream` 连接来实现的。这样做的好处是,在某些情况下,可以在一个代理上配置所有内容以使其更轻松,例如集线器和轮辐拓扑。

所有相同配置选项都适用于 `downstream`,就像适用于 `upstream` 一样,但需要设置一个额外的配置标志。

上游连接器引用

是指向在其他地方定义的 `connector` 元素的元素。此引用用于告诉下游代理使用什么连接器来创建返回下游代理的新上游连接。

连接器封装了有关使用哪种传输协议(TCP、SSL、HTTP 等)以及服务器连接参数(主机、端口等)的知识。有关连接器是什么以及如何配置它们的更多信息,请参阅 配置传输

下游地址联合示例设置

  <!--Other config Here -->

<connectors>
   <connector name="netty-connector">tcp://127.0.0.1:61616</connector>
   <connector name="eu-west-1-connector">tcp://127.0.0.1:61616</connector>
   <connector name="eu-east-1-connector">tcp://127.0.0.1:61617</connector>
</connectors>

<acceptors>
   <acceptor name="netty-acceptor">tcp://127.0.0.1:61616</acceptor>
</acceptors>

   <!--Other config Here -->

<federations>
   <federation name="eu-north-1" user="federation_username" password="32a10275cf4ab4e9">
      <downstream name="eu-east-1">
          <static-connectors>
             <connector-ref>eu-east-1-connector</connector-ref>
          </static-connectors>
          <policy ref="news-address-federation"/>
          <upstream-connector-ref>netty-connector</upstream-connector-ref>
      </downstream>
      <downstream name="eu-west-1" >
         <static-connectors>
            <connector-ref>eu-west-1-connector</connector-ref>
         </static-connectors>
         <policy ref="news-address-federation"/>
         <upstream-connector-ref>netty-connector</upstream-connector-ref>
      </downstream>

      <queue-policy name="news-queue-federation" priority-adjustment="-5" include-federated="true" transformer-ref="news-transformer">
         <include queue-match="#" address-match="queue.bbc.new" />
         <include queue-match="#" address-match="queue.usatoday" />
         <include queue-match="#" address-match="queue.news.#" />

         <exclude queue-match="#.local" address-match="#" />
      </queue-policy>

      <transformer name="news-transformer">
         <class-name>org.foo.NewsTransformer</class-name>
         <property key="key1" value="value1"/>
         <property key="key2" value="value2"/>
      </transformer>
   </federation>
</federations>