搜索

配置 AMQ Broker

download PDF
Red Hat AMQ Broker 7.10

对于使用 AMQ Broker 7.10

摘要

本指南介绍了如何配置 AMQ Broker。

使开源包含更多

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。我们从这四个术语开始:master、slave、黑名单和白名单。由于此项工作十分艰巨,这些更改将在即将推出的几个发行版本中逐步实施。有关更多详情,请参阅我们的首席技术官 Chris Wright 提供的消息

第 1 章 概述

AMQ Broker 配置文件定义代理实例的重要设置。通过编辑代理的配置文件,您可以控制代理在环境中如何工作。

1.1. AMQ Broker 配置文件和位置

所有代理的配置文件都存储在 < broker_instance_dir> /etc 中。您可以通过编辑这些配置文件中的设置来配置代理。

每个代理实例都使用以下配置文件:

broker.xml
主配置文件。您可以使用此文件配置代理的大部分方面,如网络连接、安全设置和消息地址等。
bootstrap.xml
AMQ Broker 用来启动代理实例的文件。您可以使用它来更改 broker.xml 的位置,配置 web 服务器,并设置一些安全设置。
logging.properties
您可以使用此文件为代理实例设置日志记录属性。
artemis.profile
您可以使用此文件设置代理实例运行时使用的环境变量。
login.config,artemis-users.properties,artemis-roles.properties
与安全相关的文件。您可以使用这些文件为用户访问代理实例设置身份验证。

1.2. 了解 default 代理配置

您可以通过编辑 broker.xml 配置文件来配置代理的大部分功能。此文件包含默认设置,这些设置足以启动和操作代理。但是,您可能需要更改一些默认设置,并添加新设置来为您的环境配置代理。

默认情况下,broker.xml 包含以下功能的默认设置:

  • 消息持久性
  • acceptors
  • 安全性
  • 消息地址
默认消息持久性设置

默认情况下,AMQ Broker 持久性使用仅附加的文件日志,该日志由磁盘上的一组文件组成。日志保存消息、事务和其他信息。

<configuration ...>

   <core ...>

      ...

      <persistence-enabled>true</persistence-enabled>

      <!-- this could be ASYNCIO, MAPPED, NIO
           ASYNCIO: Linux Libaio
           MAPPED: mmap files
           NIO: Plain Java Files
       -->
      <journal-type>ASYNCIO</journal-type>

      <paging-directory>data/paging</paging-directory>

      <bindings-directory>data/bindings</bindings-directory>

      <journal-directory>data/journal</journal-directory>

      <large-messages-directory>data/large-messages</large-messages-directory>

      <journal-datasync>true</journal-datasync>

      <journal-min-files>2</journal-min-files>

      <journal-pool-files>10</journal-pool-files>

      <journal-file-size>10M</journal-file-size>

      <!--
       This value was determined through a calculation.
       Your system could perform 8.62 writes per millisecond
       on the current journal configuration.
       That translates as a sync write every 115999 nanoseconds.

       Note: If you specify 0 the system will perform writes directly to the disk.
             We recommend this to be 0 if you are using journalType=MAPPED and journal-datasync=false.
      -->
      <journal-buffer-timeout>115999</journal-buffer-timeout>

      <!--
        When using ASYNCIO, this will determine the writing queue depth for libaio.
       -->
      <journal-max-io>4096</journal-max-io>

      <!-- how often we are looking for how many bytes are being used on the disk in ms -->
      <disk-scan-period>5000</disk-scan-period>

      <!-- once the disk hits this limit the system will block, or close the connection in certain protocols
           that won't support flow control. -->
      <max-disk-usage>90</max-disk-usage>

      <!-- should the broker detect dead locks and other issues -->
      <critical-analyzer>true</critical-analyzer>

      <critical-analyzer-timeout>120000</critical-analyzer-timeout>

      <critical-analyzer-check-period>60000</critical-analyzer-check-period>

      <critical-analyzer-policy>HALT</critical-analyzer-policy>

      ...

  </core>

</configuration>
默认接受设置

代理通过使用 acceptor 配置元素侦听传入客户端连接,以定义客户端可用于进行连接的端口和协议。默认情况下,AMQ Broker 包括对每个支持的消息传递协议的接受器,如下所示。

<configuration ...>

   <core ...>

      ...

      <acceptors>

        <!-- Acceptor for every supported protocol -->
        <acceptor name="artemis">tcp://0.0.0.0:61616?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=CORE,AMQP,STOMP,HORNETQ,MQTT,OPENWIRE;useEpoll=true;amqpCredits=1000;amqpLowCredits=300</acceptor>

        <!-- AMQP Acceptor. Listens on default AMQP port for AMQP traffic -->
        <acceptor name="amqp">tcp://0.0.0.0:5672?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=AMQP;useEpoll=true;amqpCredits=1000;amqpLowCredits=300</acceptor>

        <!-- STOMP Acceptor -->
        <acceptor name="stomp">tcp://0.0.0.0:61613?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=STOMP;useEpoll=true</acceptor>

        <!-- HornetQ Compatibility Acceptor. Enables HornetQ Core and STOMP for legacy HornetQ clients. -->
        <acceptor name="hornetq">tcp://0.0.0.0:5445?anycastPrefix=jms.queue.;multicastPrefix=jms.topic.;protocols=HORNETQ,STOMP;useEpoll=true</acceptor>

        <!-- MQTT Acceptor -->
        <acceptor name="mqtt">tcp://0.0.0.0:1883?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=MQTT;useEpoll=true</acceptor>

      </acceptors>

      ...

  </core>

</configuration>
默认安全设置

AMQ Broker 包含基于角色的灵活安全模型,用于根据地址将安全性应用到队列。默认配置使用通配符将 amq 角色应用到所有地址(用数字符号表示,#)。

<configuration ...>

   <core ...>

      ...

      <security-settings>
         <security-setting match="#">
            <permission type="createNonDurableQueue" roles="amq"/>
            <permission type="deleteNonDurableQueue" roles="amq"/>
            <permission type="createDurableQueue" roles="amq"/>
            <permission type="deleteDurableQueue" roles="amq"/>
            <permission type="createAddress" roles="amq"/>
            <permission type="deleteAddress" roles="amq"/>
            <permission type="consume" roles="amq"/>
            <permission type="browse" roles="amq"/>
            <permission type="send" roles="amq"/>
            <!-- we need this otherwise ./artemis data imp wouldn't work -->
            <permission type="manage" roles="amq"/>
         </security-setting>
      </security-settings>

      ...

  </core>

</configuration>
默认消息地址设置

AMQ Broker 包括一个默认地址,它会建立一组默认的配置设置以应用到任何创建的队列或主题。

此外,默认配置定义了两个队列: DLQ (Dead Letter Queue)处理消息到达已知的目的地,而 Expiry Queue 则保存过期的消息,因此不应路由到其原始目的地。

<configuration ...>

   <core ...>

      ...

      <address-settings>
         ...
         <!--default for catch all-->
         <address-setting match="#">
            <dead-letter-address>DLQ</dead-letter-address>
            <expiry-address>ExpiryQueue</expiry-address>
            <redelivery-delay>0</redelivery-delay>
            <!-- with -1 only the global-max-size is in use for limiting -->
            <max-size-bytes>-1</max-size-bytes>
            <message-counter-history-day-limit>10</message-counter-history-day-limit>
            <address-full-policy>PAGE</address-full-policy>
            <auto-create-queues>true</auto-create-queues>
            <auto-create-addresses>true</auto-create-addresses>
            <auto-create-jms-queues>true</auto-create-jms-queues>
            <auto-create-jms-topics>true</auto-create-jms-topics>
         </address-setting>
      </address-settings>

      <addresses>
         <address name="DLQ">
            <anycast>
               <queue name="DLQ" />
            </anycast>
         </address>
         <address name="ExpiryQueue">
            <anycast>
               <queue name="ExpiryQueue" />
            </anycast>
         </address>
      </addresses>

   </core>

</configuration>

1.3. 重新载入配置更新

默认情况下,代理会每 5000 毫秒检查配置文件中的更改。如果代理检测到配置文件的"上次修改"时间戳中的更改,代理将决定发生配置更改。在这种情况下,代理会重新载入配置文件来激活更改。

当代理重新载入 broker.xml 配置文件时,它会重新载入以下模块:

  • 地址设置和队列

    重新加载配置文件后,地址设置决定了如何处理从配置文件中删除的地址和队列。您可以使用 config-delete-addressesconfig-delete-queues 属性来设置它。更多信息请参阅 附录 B, 地址设置配置元素

  • 安全设置

    可以重新加载现有接受器上的 SSL/TLS 密钥存储和信任存储,以在不对现有客户端产生任何影响的情况下建立新证书。连接的客户端(即使具有较旧或不同证书的人员)也可以继续发送和接收信息。

  • 竞争

    配置重新加载会部署您添加的 任何新 分项。但是,在重启代理前,从配置中删除 对子元素的更改不会生效。

以下流程演示了如何更改代理检查对 broker.xml 配置文件的更改的时间间隔。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 在 & lt;core > 元素中添加 <configuration-file-refresh-period > 元素并设置刷新周期(以毫秒为单位)。

    这个示例将配置刷新周期设置为 60000 毫秒:

    <configuration>
        <core>
            ...
            <configuration-file-refresh-period>60000</configuration-file-refresh-period>
            ...
        </core>
    </configuration>

如果由于某种原因而无法访问配置文件,也可以使用 Management API 或控制台重新加载配置文件。可以使用 ActiveMQServerControl 上的管理操作 reloadConfigurationFile() 来重新加载配置文件(使用 ObjectName org.apache.activemq.artemis:broker="BROKER_NAME" 或 resource name server

其他资源

  • 要了解如何使用管理 API,请参阅在管理 AMQ Broker 中使用 Management API

1.4. 修改代理配置文件

如果您有多个共享通用配置设置的代理,您可以在单独的文件中定义通用配置,然后将这些文件包括在每个代理的 broker.xml 配置文件中。

您可以在代理间共享的最常见配置设置包括:

  • 地址
  • 地址设置
  • 安全设置

流程

  1. 为您想共享的每个 broker.xml 部分创建单独的 XML 文件。

    每个 XML 文件只能包含来自 broker.xml 的单个部分(例如,地址或地址设置,但不能同时包含两者)。顶级元素还必须定义 element 命名空间(xmlns="urn:activemq:core")。

    本例演示了 my-security-settings.xml 中定义的安全设置配置:

    my-security-settings.xml

    <security-settings xmlns="urn:activemq:core">
       <security-setting match="a1">
          <permission type="createNonDurableQueue" roles="a1.1"/>
       </security-setting>
       <security-setting match="a2">
          <permission type="deleteNonDurableQueue" roles="a2.1"/>
       </security-setting>
    </security-settings>

  2. 为每个应使用通用配置设置的代理打开 & lt;broker_instance_dir> /etc/broker.xml 配置文件。
  3. 对于您打开的每个 broker.xml 文件,请执行以下操作:

    1. broker.xml 开头的 < configuration > 元素中验证是否显示以下行:

      xmlns:xi="http://www.w3.org/2001/XInclude"
    2. 为每个包含共享配置设置的 XML 文件添加 XML。

      这个示例包括 my-security-settings.xml 文件。

      broker.xml

      <configuration ...>
          <core ...>
              ...
              <xi:include href="/opt/my-broker-config/my-security-settings.xml"/>
              ...
          </core>
      </configuration>

    3. 如果需要,验证 broker.xml,以验证 XML 是否对 schema 有效。

      您可以使用任何 XML 验证程序。这个示例使用 xmllintartemis-server.xsl 模式验证 broker.xml

      $ xmllint --noout --xinclude --schema /opt/redhat/amq-broker/amq-broker-7.2.0/schema/artemis-server.xsd /var/opt/amq-broker/mybroker/etc/broker.xml
      /var/opt/amq-broker/mybroker/etc/broker.xml validates

其他资源

1.4.1. 重新加载模块配置文件

当代理定期检查配置更改(根据 config-file-refresh-period 指定的频率),它不会自动检测通过 xi:includebroker.xml 配置文件中包含的配置文件的变化。例如,如果 broker.xml 包含 my-address-settings.xml,并且您对 my-address-settings.xml 进行配置更改,则代理不会自动检测 my-address-settings.xml 中的更改并重新载入配置。

要强制 重新加载 broker.xml 配置文件以及其中包含的任何修改的配置文件,您必须确保 broker.xml 配置文件的"last modified"时间戳已改变。您可以使用标准 Linux touch 命令更新 broker.xml 的最后修改时间戳,而无需进行任何更改。例如:

$ touch -m <broker_instance_dir>/etc/broker.xml

或者您可以使用管理 API 来强制重新加载代理。可以使用 ActiveMQServerControl 上的管理操作 reloadConfigurationFile() 来重新加载配置文件(使用 ObjectName org.apache.activemq.artemis:broker="BROKER_NAME" 或 resource name server

其他资源

  • 要了解如何使用管理 API,请参阅在管理 AMQ Broker 中使用 Management API

1.5. 文档惯例

本文档对 sudo 命令、文件路径和可替换值使用以下惯例:

sudo 命令

在本文档中,sudo 用于任何需要 root 特权的命令。使用 sudo 时,您应始终谨慎操作,因为任何更改都可能会影响整个系统。

有关使用 sudo 的更多信息,请参阅管理 sudo 访问

关于在此文档中使用文件路径

在这个文档中,所有文件路径都对 Linux、UNIX 和类似操作系统(例如 /home/...)有效。如果您使用的是 Microsoft Windows,则应使用等效的 Microsoft Windows 路径(例如,C:\Users\...)。

可替换值

本文档有时会使用可替换值,您必须将这些值替换为特定于环境的值。可替换的值为小写,以尖括号(<>)括起,样式则使用斜体和 monospace 字体。用下划线(_)分隔多个词语。

例如,在以下命令中,将 <install_dir> 替换为您自己的目录名称。

$ <install_dir>/bin/artemis create mybroker

第 2 章 在网络连接中配置接收器和连接器

AMQ Broker 中使用的两种连接类型:网络连接 和虚拟机 连接。当双方位于不同的虚拟机中时,会使用网络连接,无论在同一服务器还是物理远程上。当客户端(应用程序还是服务器)位于与代理相同的虚拟机上时,会使用 in-VM 连接。

网络连接使用 Netty。Netty 是一个高性能、低级网络库,它允许以几种不同的方式配置网络连接;使用 Java IO 或 NIO、TCP 套接字、SSL/TLS 或隧道通过 HTTP 或 HTTPS 进行隧道。Netty 还支持单一端口用于所有消息协议。代理将自动检测正在使用的协议,并将传入的消息定向到适当的处理器,以便进一步处理。

网络连接的 URI 确定其类型。例如,在 URI 中指定 vm 会创建一个 in-VM 连接:

<acceptor name="in-vm-example">vm://0</acceptor>

另外,在 URI 中指定 tcp 会创建网络连接。例如:

<acceptor name="network-example">tcp://localhost:61617</acceptor>

以下部分描述了网络连接和虚拟机连接所需的两个重要配置元素; 接收器连接器。这些部分介绍了如何为 TCP、HTTP 和 SSL/TLS 网络连接配置接收器和连接器,以及虚拟机内连接。

2.1. 关于接收器

接收器 ( acceptors)定义如何对代理进行连接。每个接受者定义客户端可用于建立连接的端口和协议。简单接受器配置如下所示。

<acceptors>
   <acceptor name="example-acceptor">tcp://localhost:61617</acceptor>
</acceptors>

您在代理配置中定义的每个 acceptor 元素都包含在一个 接收器 元素中。您可以为代理定义的接受者数量没有上限。默认情况下,AMQ Broker 包括对每个支持的消息传递协议的接受器,如下所示:

<configuration ...>
   <core ...>
      ...
      <acceptors>
        ...
        <!-- Acceptor for every supported protocol -->
        <acceptor name="artemis">tcp://0.0.0.0:61616?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=CORE,AMQP,STOMP,HORNETQ,MQTT,OPENWIRE;useEpoll=true;amqpCredits=1000;amqpLowCredits=300</acceptor>

        <!-- AMQP Acceptor. Listens on default AMQP port for AMQP traffic -->
        <acceptor name="amqp">tcp://0.0.0.0:5672?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=AMQP;useEpoll=true;amqpCredits=1000;amqpLowCredits=300</acceptor>

        <!-- STOMP Acceptor -->
        <acceptor name="stomp">tcp://0.0.0.0:61613?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=STOMP;useEpoll=true</acceptor>

        <!-- HornetQ Compatibility Acceptor. Enables HornetQ Core and STOMP for legacy HornetQ clients. -->
        <acceptor name="hornetq">tcp://0.0.0.0:5445?anycastPrefix=jms.queue.;multicastPrefix=jms.topic.;protocols=HORNETQ,STOMP;useEpoll=true</acceptor>

        <!-- MQTT Acceptor -->
        <acceptor name="mqtt">tcp://0.0.0.0:1883?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=MQTT;useEpoll=true</acceptor>
      </acceptors>
      ...
  </core>
</configuration>

2.2. 配置接收器

以下示例演示了如何配置接收器。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. acceptors 元素中,添加新的 acceptor 元素。指定代理中的一个协议和端口。例如:

    <acceptors>
       <acceptor name="example-acceptor">tcp://localhost:61617</acceptor>
    </acceptors>

    前面的示例定义了 TCP 协议的接受者。代理在端口 61617 中侦听使用 TCP 的客户端连接。

  3. 将键值对附加到为接受者定义的 URI。使用分号(;)来分隔多个键值对。例如:

    <acceptor name="example-acceptor">tcp://localhost:61617?sslEnabled=true;key-store-path=</path/to/key_store></acceptor>

    配置现在定义了使用 TLS/SSL 的接受器,并定义所需密钥存储的路径。

其他资源

2.3. 关于连接器

acceptors 定义代理如何接受连接,客户端使用的连接器定义它们如何连接到一个代理。

当代理本身作为客户端操作时,会在代理中配置连接器。例如:

  • 当代理桥接到另一个代理时
  • 当代理在集群中处理部分时

简单的连接器配置如下所示。

<connectors>
   <connector name="example-connector">tcp://localhost:61617</connector>
</connectors>

2.4. 配置连接器

以下示例演示了如何配置连接器。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 连接器 元素中,添加新的 连接器 元素。指定代理中的一个协议和端口。例如:

    <connectors>
       <connector name="example-connector">tcp://localhost:61617</connector>
    </connectors>

    前面的示例为 TCP 协议定义了一个连接器。客户端可以使用连接器配置使用 TCP 协议连接到端口 61617 上的代理。代理本身也可以将这个连接器用于出站连接。

  3. 将键值对附加到为连接器定义的 URI。使用分号(;)来分隔多个键值对。例如:

    <connector name="example-connector">tcp://localhost:61616?tcpNoDelay=true</connector>

    现在,配置定义了将 tcpNoDelay 属性的值设置为 true 的连接器。将此属性的值设置为 true 可关闭连接的算法。Nagle 的算法是一种算法,用于通过延迟小数据数据包传输并整合到大型数据包来提高 TCP 连接效率。

其他资源

2.5. 配置 TCP 连接

AMQ Broker 使用 Netty 提供基本、未加密的基于 TCP 的连接性,该连接可以配置为使用 Java IO 或较新的非阻塞 Java NIO。Java NIO 最好与许多并发连接更好地扩展。但是,使用旧的 IO 有时当您不必支持数以千计的并发连接时,可以比 NIO 提供更好的延迟。

如果您在不可信网络中运行连接,您应该注意 TCP 网络连接是未加密的的。如果安全性是优先级,您可能需要考虑使用 SSL 或 HTTPS 配置加密通过这个连接发送的消息。详情请查看 第 5.1 节 “保护连接”

使用 TCP 连接时,客户端启动所有连接。代理不会启动到客户端的任何连接。这非常适合于强制从一个方向启动连接的防火墙策略。

对于 TCP 连接,主机以及连接器 URI 的端口定义用于连接的地址。

以下示例演示了如何配置 TCP 连接。

先决条件

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 添加新接受者或修改现有接受者。在连接 URI 中,指定 tcp 作为协议。同时包括 IP 地址或主机名以及代理上的端口。例如:

    <acceptors>
      <acceptor name="tcp-acceptor">tcp://10.10.10.1:61617</acceptor>
      ...
    </acceptors>

    根据上例,代理接受来自客户端在 IP 地址 10.10.10.1 上的端口 61617 的 TCP 通信。

  3. (可选)您可以以类似的方式配置连接器。例如:

    <connectors>
      <connector name="tcp-connector">tcp://10.10.10.2:61617</connector>
      ...
    </connectors>

    上例中的连接器被客户端(甚至代理本身)引用,在向指定的 IP 和端口 10.10.10.2:61617 进行 TCP 连接时。

其他资源

2.6. 配置 HTTP 连接

HTTP 连接隧道数据包通过 HTTP 协议,在防火墙只允许 HTTP 流量的情况下非常有用。AMQ Broker 会自动检测 HTTP 是否被使用,因此为 HTTP 配置网络连接与为 TCP 配置连接相同。

先决条件

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 添加新接受者或修改现有接受者。在连接 URI 中,指定 tcp 作为协议。同时包括 IP 地址或主机名以及代理上的端口。例如:

    <acceptors>
      <acceptor name="http-acceptor">tcp://10.10.10.1:80</acceptor>
      ...
    </acceptors>

    根据上例,代理接受来自客户端的 HTTP 通信连接到 IP 地址 10.10.10.1 的端口 80。代理自动检测到 HTTP 协议正在使用中,并相应地与客户端通信。

  3. (可选)您可以以类似的方式配置连接器。例如:

    <connectors>
      <connector name="http-connector">tcp://10.10.10.2:80</connector>
      ...
    </connectors>

    使用上例中显示的连接器,代理在端口 80 上通过 IP 地址 10.10.10.2 创建出站 HTTP 连接。

其他资源

  • HTTP 连接使用与 TCP 相同的配置参数,但也有一些本身。有关 HTTP 连接所有可用配置选项的详情,请参考 附录 A, acceptor 和 Connector 配置参数
  • 有关如何使用 HTTP 的完整工作示例,请查看位于代理安装的 < install_dir>/examples/features/standard/ 目录中的 http-transport 示例。

2.7. 配置安全网络连接

您可以使用 TLS/SSL 保护网络连接。更多信息请参阅 第 5.1 节 “保护连接”

2.8. 配置虚拟机连接

当多个代理位于相同虚拟机上时,您可以使用一个 in-VM 连接,例如,作为高可用性(HA)配置的一部分。在与代理相同的 JVM 中运行的本地客户端也可以使用 in-VM 连接。

先决条件

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 添加新接受者或修改现有接受者。在连接 URI 中,将 vm 指定为协议。例如:

    <acceptors>
      <acceptor name="in-vm-acceptor">vm://0</acceptor>
      ...
    </acceptors>

    根据上例中的 acceptor,代理接受来自带有 ID 0 的代理的连接。其他代理必须在同一虚拟机上运行。

  3. (可选)您可以以类似的方式配置连接器。例如:

    <connectors>
      <connector name="in-vm-connector">vm://0</connector>
      ...
    </connectors>

    上例中的连接器定义了客户端如何将一个到 ID 为 0 的代理建立到与客户端相同的虚拟机上运行的代理。客户端可以是应用程序或其他代理。

第 3 章 在网络连接中配置消息协议

AMQ Broker 具有可插拔协议架构,以便您可以轻松为网络连接启用一个或多个协议。

代理支持以下协议:

注意

除了上面的协议,代理还支持自己的原生协议,称为"Core"。此协议的过去版本被称为"HornetQ",并由红帽 JBoss 企业应用平台使用。

3.1. 配置网络连接以使用消息传递协议

您必须将协议与网络连接关联,然后才能使用它。(请参阅 第 2 章 在网络连接中配置接收器和连接器 以了解有关如何创建和配置网络连接的更多信息。)位于 < broker_instance_dir> /etc/broker.xml 文件中的默认配置,包括已经定义了多个连接。为方便起见,AMQ Broker 包括对每个支持的协议的接受器,以及一个支持所有协议的默认接受器。

默认接收器概述

下面是在 broker.xml 配置文件中默认包括的接收器。

<configuration>
  <core>
    ...
    <acceptors>

      <!-- All-protocols acceptor -->
      <acceptor name="artemis">tcp://0.0.0.0:61616?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=CORE,AMQP,STOMP,HORNETQ,MQTT,OPENWIRE;useEpoll=true;amqpCredits=1000;amqpLowCredits=300</acceptor>

      <!-- AMQP Acceptor. Listens on default AMQP port for AMQP traffic -->
      <acceptor name="amqp">tcp://0.0.0.0:5672?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=AMQP;useEpoll=true;amqpCredits=1000;amqpLowCredits=300</acceptor>

      <!-- STOMP Acceptor -->
      <acceptor name="stomp">tcp://0.0.0.0:61613?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=STOMP;useEpoll=true</acceptor>

      <!-- HornetQ Compatibility Acceptor. Enables HornetQ Core and STOMP for legacy HornetQ clients. -->
      <acceptor name="hornetq">tcp://0.0.0.0:5445?anycastPrefix=jms.queue.;multicastPrefix=jms.topic.;protocols=HORNETQ,STOMP;useEpoll=true</acceptor>

      <!-- MQTT Acceptor -->
      <acceptor name="mqtt">tcp://0.0.0.0:1883?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=MQTT;useEpoll=true</acceptor>

    </acceptors>
    ...
  </core>
</configuration>

在给定网络连接器中启用协议的唯一要求是,将 protocol 参数添加到接受者的 URI 中。参数的值必须是用逗号分开的协议名称列表。如果在 URI 中省略了 protocol 参数,则启用所有协议。

例如,要创建使用 AMQP 协议在端口 3232 上接收消息的接受者,请按照以下步骤操作:

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 在 < acceptors& gt; 小节中添加以下行:
<acceptor name="ampq">tcp://0.0.0.0:3232?protocols=AMQP</acceptor>
默认接受者中的其他参数

在最小接受器配置中,您将指定协议作为连接 URI 的一部分。但是,broker.xml 配置文件中的 default acceptors 已配置了一些附加参数。下表详细介绍了为默认接收器配置的其他参数。

接受者参数描述

all-protocols acceptor

AMQP

STOMP

tcpSendBufferSize

TCP 发送缓冲区的大小(以字节为单位)。默认值为 32768

tcpReceiveBufferSize

TCP 接收缓冲区的大小(以字节为单位)。默认值为 32768

TCP 缓冲区大小应该根据网络的带宽和延迟调整。

在概述 TCP 发送/接收方缓冲区大小中,应计算如下:

buffer_size = bandwidth * RTT.

其中带宽为每秒字节数,网络往返时间(RTT)以秒为单位。RTT 可以使用 ping 程序轻松测量。

对于快速网络,您可能想要从默认设置中增加缓冲区大小。

all-protocols acceptor

AMQP

STOMP

HornetQ

MQTT

useEpoll

如果使用支持它的系统(Linux),请使用 Netty epoll。Netty 原生传输提供了优于 NIO 传输的性能。这个选项的默认值是 true。如果将 选项设置为 false,则使用 NIO。

all-protocols acceptor

AMQP

amqpCredits

AMQP 生产者可以发送的最大消息数量,而不考虑消息总数。默认值为 1000

要了解有关如何使用贡献范围来阻止 AMQP 信息的更多信息,请参阅 第 7.3.2 节 “阻塞 AMQP 生产者”

all-protocols acceptor

AMQP

amqpLowCredits

降低代理重新制作者学分的阈值。默认值为 300。当制作者达到这个阈值时,代理会发送生产者足够的贡献度,以恢复 amqpCredits 值。

要了解有关如何使用贡献范围来阻止 AMQP 信息的更多信息,请参阅 第 7.3.2 节 “阻塞 AMQP 生产者”

HornetQ 兼容性接受者

anycastPrefix

当连接到一个使用 anycastmulticast 地址时,客户端用来指定 anycast 路由类型的前缀。默认值为 jms.queue

有关配置前缀以启用客户端在连接到地址时指定路由类型的更多信息,请参阅 第 4.6 节 “在接受器配置中添加路由类型”

multicastPrefix

当连接到一个使用 anycastmulticast 地址时,客户端用来指定 multicast 路由类型的前缀。默认值为 jms.topic

有关配置前缀以启用客户端在连接到地址时指定路由类型的更多信息,请参阅 第 4.6 节 “在接受器配置中添加路由类型”

其他资源

3.2. 使用带有网络连接的 AMQP

代理支持 AMQP 1.0 规格。AMQP 链接是用于源与目标(即客户端和代理)之间的消息的单向协议。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 添加或配置一个 acceptor 来接收 AMQP 客户端,方法是包括一个值为 AMQPprotocols 参数作为 URI 的一部分。如下例所示:
<acceptors>
  <acceptor name="amqp-acceptor">tcp://localhost:5672?protocols=AMQP</acceptor>
  ...
</acceptors>

在前面的示例中,代理接受端口 5672 上的 AMQP 1.0 客户端,这是默认的 AMQP 端口。

AMQP 链接有两个端点,一个发送者和一个接收器。当发件人传输消息时,代理会将其转换为内部格式,因此可以转发到代理上的目的地。接收器连接到代理上的目的地,并在发送信息前将其转换为 AMQP。

如果 AMQP 链接是动态的,则创建一个临时队列,并将远程源或远程目标地址设置为临时队列的名称。如果链接不是动态的,则远程目标或源的地址将用于队列。如果远程目标或源不存在,则会发送异常。

链接目标也可以是协调器,用于将底层会话作为事务处理,可以是回滚或提交它。

注意

AMQP 允许为每个会话使用多个事务,amqp:multi-txns-per-ssn,但 AMQ Broker 的当前版本将只支持每个会话的单一事务。

注意

AMQP 中的分布式事务(XA)详情在规格的 1.0 版本中没有提供。如果您的环境需要支持分布式事务,建议您使用 AMQ 核心协议 JMS。

有关协议及其功能的更多信息,请参阅 AMQP 1.0 规格。

3.2.2. 配置 AMQP 安全性

代理支持 AMQP SASL 身份验证。有关如何在代理中配置基于 SASL 的身份验证的详情,请参阅 安全性

3.3. 使用带有网络连接的 awx

代理支持 MCG v3.1.1 和 v5.0(以及旧的 v3.1 代码消息格式)。PlacementBinding 是服务器、发布/订阅消息协议的轻量级客户端。替代消息传递开销和网络流量,以及客户端的代码占用量。出于这些原因,include 非常适合约束其设备,如传感器和传感器,并很快成为物联网(IoT)的事实标准通信协议。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 添加接受者,并启用了 IFL 协议。例如:
<acceptors>
  <acceptor name="mqtt">tcp://localhost:1883?protocols=MQTT</acceptor>
  ...
</acceptors>

PlacementBinding 随附一些有用的功能,其中包括:

服务质量
每个消息都可以定义与之关联的服务质量。代理将尝试在定义的最高服务质量时向订阅者发送消息。
保留的消息
可为特定地址保留消息。此地址的新订阅者接收最后一封保留的消息,然后任何其他消息,即使保留的消息是在客户端连接之前发送的。
通配符订阅
LAST 地址是层级的,类似于文件系统的层次结构。客户可以订阅特定主题或层次结构的整个分支。
将消息
客户端可以将"will message"设置为其连接数据包的一部分。如果客户端异常断开连接,代理会将消息发布到指定的地址。其他订阅者收到一条信息,并可以相应地作出反应。

有关 IFL 协议的更多信息,请参阅规格。

3.3.1. 配置 paper 属性

您可以将键值对附加到 IFL 接受器以配置连接属性。例如:

<acceptors>
  <acceptor name="mqtt">tcp://localhost:1883?protocols=MQTT;receiveMaximum=50000;topicAliasMaximum=50000;maximumPacketSize;134217728;
serverKeepAlive=30;closeMqttConnectionOnPublishAuthorizationFailure=false</acceptor>
  ...
</acceptors>
receiveMaximum
通过在需要确认前,指定代理可以从客户端接收的 QoS 1 和 2 信息来启用流控制。默认值为 65535。值 -1 将禁用从客户端到代理的流控制。这与将值设为 0 的效果相同,但会减少 CONNACK 数据包的大小。
topicAliasMaximum
为客户端指定代理支持的最大别名数。默认值为 65535。值 -1 可防止代理向客户端发出主题别名限制。这与将值设为 0 的效果相同,但会减少 CONNACK 数据包的大小。
maximumPacketSize
指定代理可以从客户端接受的最大数据包大小。默认值为 268435455。值 -1 可防止代理向客户端发送最大数据包大小,这意味着在传入的数据包大小上不会强制实施限制。
serverKeepAlive
指定代理保持不活跃客户端连接的持续时间。只有在配置的值小于为客户端配置的 keep-alive 值,或者为客户端配置的值是 0。默认值为 60 秒。值 -1 表示代理始终接受客户端持续值(即使该值为 0)。
closeMqttConnectionOnPublishAuthorizationFailure
默认情况下,如果因为缺少授权而导致 PUBLISH 数据包失败,代理会关闭网络连接。如果您希望代理发送正确认而不是关闭网络连接,请将 closeMqttConnectionOnPublishAuthorizationFailure 设置为 false

3.4. 使用带有网络连接的 OpenWire

代理支持 OpenWire 协议,它允许 JMS 客户端直接与代理通信。使用此协议与较旧版本的 AMQ Broker 进行通信。

目前,AMQ Broker 支持仅使用标准 JMS API 的 OpenWire 客户端。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 添加或修改一个 acceptor,使其包含 OPENWIRE 作为 protocol 参数的一部分,如下例所示:

    <acceptors>
      <acceptor name="openwire-acceptor">tcp://localhost:61616?protocols=OPENWIRE</acceptor>
      ...
    </acceptors>

在前面的示例中,代理将监听端口 61616 用于传入的 OpenWire 命令。

如需了解更多详细信息,请参阅位于 < install_dir> /examples/protocols/openwire 下的示例。

3.5. 使用带有网络连接的 STOMP

STOMP 是一个基于文本的识别线协议,允许 STOMP 客户端与 STOMP Broker 通信。代理支持 STOMP 1.0、1.1 和 1.2。STOMP 客户端适用于多种语言和平台,使其成为可互操作性的良好选择。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 配置现有的 接收器 或创建新接收器,并包含一个 protocol 参数,其值为 STOMP,如下所示。
<acceptors>
  <acceptor name="stomp-acceptor">tcp://localhost:61613?protocols=STOMP</acceptor>
  ...
</acceptors>

在上例中,代理接受端口 61613 上的 STOMP 连接,这是默认值。

有关使用 STOMP 配置代理的示例,请参阅 <install_dir>/examples/protocols 下的 stomp 示例。

3.5.1. STOMP 限制

使用 STOMP 时,会有以下限制:

  1. 代理目前不支持虚拟主机,这意味着 CONNECT 帧中的 host 标头被忽略。
  2. 消息确认不是事务。ACK 帧不能是事务的一部分,如果设置了 事务 标头,它将会被忽略。

3.5.2. 为 STOMP 信息提供 ID

当通过 JMS 使用者或 QueueBrowser 接收 STOMP 消息时,消息不包含任何 JMS 属性,例如 JMSMessageID。但是,您可以使用代理 paramater 在每个传入的 STOMP 消息上设置消息 ID。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 对于用于 STOMP 连接的 acceptor,将 stompEnableMessageId 参数设置为 true,如下例所示:
<acceptors>
  <acceptor name="stomp-acceptor">tcp://localhost:61613?protocols=STOMP;stompEnableMessageId=true</acceptor>
  ...
</acceptors>

通过使用 stompEnableMessageId 参数,使用此接受器发送的每个 stomp 消息都会添加额外属性。属性键是 amq-message-id,值是前缀为 "STOMP" 的内部消息 ID 的 String 表示,如下例所示:

amq-message-id : STOMP12345

如果在配置中没有指定 stompEnableMessageId,则默认值为 false

3.5.3. 将连接时间设置为实时

STOMP 客户端必须在关闭连接前发送 DISCONNECT 帧。这允许代理关闭任何服务器端资源,如会话和消费者。但是,如果 STOMP 客户端在不发送 DISCONNECT 帧的情况下退出,或者如果它们失败,代理将无法立即知道客户端是否仍处于活动状态。因此,STOMP 连接配置为将 "Time to Live"(TTL)配置为 1 分钟。这意味着,如果代理闲置超过 1 分钟,代理会停止与 STOMP 客户端的连接。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. connectionTTL 参数添加到用于 STOMP 连接的 acceptor 的 URI,如下例所示:
<acceptors>
  <acceptor name="stomp-acceptor">tcp://localhost:61613?protocols=STOMP;connectionTTL=20000</acceptor>
  ...
</acceptors>

在前面的示例中,任何使用 stomp-acceptor 的 stomp 连接都将其 TTL 设置为 20 秒。

注意

STOMP 协议的版本 1.0 不包含任何心跳帧。因此,用户责任确保在 connection-ttl 中发送数据,或者代理会假定客户端已死机并清理服务器端资源。对于版本 1.1,您可以使用 Core-beats 来维护 stomp 连接的生命周期。

将代理默认时间覆盖到实时

如前所述,STOMP 连接的默认 TTL 为一分钟。您可以通过在代理配置中添加 connection-ttl-override 属性来覆盖这个值。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 添加 connection-ttl-override 属性,为新默认值提供值(毫秒)。它属于 < core&gt; 小节,如下所示。
<configuration ...>
  ...
  <core ...>
    ...
    <connection-ttl-override>30000</connection-ttl-override>
    ...
  </core>
<configuration>

在前面的示例中,STOMP 连接的默认生存时间(TTL)被设置为 30 秒,30000 毫秒。

3.5.4. 从 JMS 发送和接收 STOMP 消息

STOMP 主要是一个基于文本的协议。为了便于与 JMS 互操作,STOMP 实现检查是否存在 内容长度 的标头,以确定如何将 STOMP 消息映射到 JMS。

如果您希望 STOMP 消息映射到 …​消息 should…​.

JMS TextMessage

不包括 内容长度 的标头。

JMS BytesMessage

包括一个 content-length 标头。

将 JMS 消息映射到 STOMP 时相同的逻辑。STOMP 客户端可以确认是否存在 内容长度 标头,以确定消息正文类型(字符串或字节数)。

有关消息标头的更多信息,请参阅 STOMP 规格。

3.5.5. 将 STOMP 目的地映射到 AMQ Broker 地址和队列

在发送消息和订阅时,STOMP 客户端通常包含一个目标 标头。目的地名称是字符串值,它们映射到代理上的目的地。在 AMQ Broker 中,这些目的地映射到 addressesqueues。有关目的地帧的更多信息,请参阅 STOMP 规格。

使用发送以下消息的 STOMP 客户端(headers 和正文包括):

SEND
destination:/my/stomp/queue

hello queue a
^@

在这种情况下,代理会将消息转发到与地址 /my/stomp/queue 相关联的任何队列。

例如,当 STOMP 客户端发送一条信息(使用 SEND 帧)时,指定的目的地被映射到地址。

当客户端发送 SUBSCRIBEUNSUBSCRIBE 帧时,它的工作方式相同,但在本例中,AMQ Broker 会将 目的地 映射到队列。

SUBSCRIBE
destination: /other/stomp/queue
ack: client

^@

在前面的示例中,代理会将 目的地 映射到队列 /other/stomp/queue

将 STOMP 目的地映射到 JMS 目的地

JMS 目的地也映射到代理地址和队列。如果要使用 STOMP 发送消息到 JMS 目的地,STOMP 目的地必须遵循相同的约定:

  • 通过添加queue.queue . 的队列名称来发送或订阅 JMS Queue。例如,要向 订购 JMS Queue 发送消息,STOMP 客户端必须发送该帧:

    SEND
    destination:jms.queue.orders
    hello queue orders
    ^@
  • 通过在 主题 名称前面加上 jms.topic.,发送或订阅 JMS 主题。例如,要订阅 库存 JMS 主题,STOMP 客户端必须发送类似如下的帧:

    SUBSCRIBE
    destination:jms.topic.stocks
    ^@

第 4 章 配置地址和队列

4.1. 地址、队列和路由类型

在 AMQ Broker 中,寻址模型包含三个主要概念: 地址队列路由类型

地址 代表消息传递端点。在配置中,为典型的地址指定唯一名称、一个或多个队列,以及路由类型。

队列与 地址相关联。每个地址可以有多个队列。传入的消息与地址匹配后,该消息将发送到一个或多个队列,具体取决于配置的路由类型。可以将队列配置为自动创建和删除队列。您还可以配置一个地址(以及其关联队列)作为 durable。只要队列中的消息也持久存在,durable 队列中的消息可在崩溃或重启代理后保留。与之相反,即使消息本身是持久的,队列中的消息不会在崩溃或重启代理后保留。

路由类型 决定了如何将消息发送到与地址关联的队列。在 AMQ Broker 中,您可以使用两个不同的路由类型配置地址,如表所示。

如果您希望您的消息路由到…​使用此路由类型…​

匹配地址内的单个队列,以点对点的方式

任播

匹配地址中的每个队列,以发布订阅的方式

multicast

注意

地址必须至少有一个定义的路由类型。

每个地址可以定义多个路由类型,但不推荐这样做。

如果一个地址同时定义了两个路由类型,并且客户端没有其首选项,则代理会默认使用 multicast 类型。

其他资源

4.1.1. 地址和队列命名要求

在配置地址和队列时请注意以下要求:

  • 要确保客户端可以连接到队列,无论客户端使用的有线协议,您的地址和 队列名称不应 包括以下任意字符:

    & :: , ? >

  • 数字符号(#)和星号(*)字符保留给通配符表达式,不应在地址和队列名称中使用。更多信息请参阅 第 4.2.1 节 “AMQ Broker 通配符语法”
  • 地址和队列名称不应包含空格。
  • 要在地址或队列名称中分隔词语,请使用配置的分隔符。默认分隔符为句点(.)。更多信息请参阅 第 4.2.1 节 “AMQ Broker 通配符语法”

4.2. 将地址设置应用到一组地址

在 AMQ Broker 中,您可以通过使用通配符表达式来代表匹配的地址名称,将 address-setting 元素中指定的配置应用到 一组 地址。

以下小节论述了如何使用通配符表达式。

4.2.1. AMQ Broker 通配符语法

AMQ Broker 使用特定的语法来代表地址设置中的通配符。通配符也可以在安全设置中使用,也可以在创建用户时使用。

  • 通配符表达式包含句点(.)分隔的词语。
  • 数字符号(#)和星号(*)字符也有特殊含义,并可以取一个单词的位置,如下所示:

    • 数字符号字符表示"匹配任何零个或多个单词序列"。在表达式的末尾使用它。
    • 星号字符表示"匹配单个单词"。在您的表达式的任意位置使用此名称。

匹配不是按字符来完成的,而是在每个分隔符之外。例如,配置为匹配名称中 my 的队列的 address-setting 元素与名为 myqueue 的队列 不匹配

当多个 address-setting 元素匹配地址时,代理覆盖配置将最小特定匹配配置为基准。字面表达式比通配符更具体,而星号(*)比一个数字符号(#)更为具体。例如,my.destinationmy.* 都与 my.destination 的地址匹配。在这种情况下,代理首先应用在 my.* 下找到的配置,因为通配符表达式小于字面值。接下来,代理会覆盖 my.destination address 设置元素的配置,该元素会覆盖与 my.* 共享的任何配置。例如,给定以下配置,与 my.destination 关联的队列将 max-delivery-attempts 设置为 3last-value-queue 设置为 false

<address-setting match="my.*">
    <max-delivery-attempts>3</max-delivery-attempts>
    <last-value-queue>true</last-value-queue>
</address-setting>
<address-setting match="my.destination">
    <last-value-queue>false</last-value-queue>
</address-setting>

下表示例中的示例说明了使用通配符来匹配一组地址。

示例描述

#

broker.xml 中使用的默认 address-setting :匹配每个地址。您可以继续应用这个 catch-all,或者您可以根据需要为每个地址或组添加一个新的 address-setting

news.europe.#

news.europe,news.europe.sport,news.europe.fr 匹配,但不能使用 news.usaeurope

news.*

匹配 news.europenews.usa,但不匹配 news.europe.sport

news.*.sport

匹配 news.europe.sportnews.usa.sport,但不能使用 news.europe.fr.sport

4.2.2. 配置代理通配符语法

以下流程演示了如何自定义用于通配符地址的语法。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 在配置中添加 <wildcard-addresses > 部分,如下例所示。

    <configuration>
      <core>
        ...
        <wildcard-addresses> //
          <enabled>true</enabled> //
          <delimiter>,</delimiter> //
          <any-words>@</any-words> //
          <single-word>$</single-word>
        </wildcard-addresses>
        ...
      </core>
    </configuration>
    enabled
    当设置为 true 时,指示代理使用您的自定义设置。
    delimiter
    提供自定义字符作为 分隔符 替代默认字符(.)。
    任意词语
    提供的字符作为 任意词语 的值用于表示"匹配任何零个或多个单词序列",并替换默认的 #。在表达式的末尾使用此字符。
    single-word
    提供的字符作为 单词语 值的字符用于表示"匹配单个单词",并将替换默认的 *。在您的表达式的任意位置使用此字符。

4.3. 为点到点的消息传递配置地址

点对点消息传递是一种常见的场景,由制作者发送的消息仅包含一个消费者。AMQP 和 JMS 消息制作者和消费者可以利用点对点的消息传递队列,例如:为确保在点到点的方式中队列与一个接收消息的地址相关联,在您的代理配置中为给定的 address项定义一个 anycast 路由类型。

当消息在一个使用 anycast 的地址上接收时,代理会找到与地址关联的队列,并将消息路由到它。然后,消费者可能会请求消耗来自该队列的消息。如果多个消费者连接到同一队列,则消息会平等地分布在消费者之间,只要消费者可以平等地处理它们。

下图显示了点对点的消息传递示例。

点到点消息

4.3.1. 配置基本点到点消息传递

以下流程演示了如何为点到点消息传递配置单一队列的地址。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 使用一个 address 所选的 queue 项环绕一个 anycast 配置项。确保 地址 和队列 元素的 name 属性的值相同。例如:

    <configuration ...>
      <core ...>
        ...
        <address name="my.anycast.destination">
          <anycast>
            <queue name="my.anycast.destination"/>
          </anycast>
        </address>
      </core>
    </configuration>

4.3.2. 为多个队列配置点对点的消息传递

您可以在使用 anycast 路由类型的地址上定义多个队列。代理将发送到所有关联的队列中的 任播 地址平均分布。通过指定 完全限定域名 (FQQN),您可以将客户端连接到特定队列。如果多个消费者连接到同一队列,则代理会在使用者之间平均分配消息。

下图显示了使用两个队列的点对点消息传递的示例。

指向使用多个队列的消息传递

以下流程演示了如何为具有多个队列的地址配置点对点的消息传递。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 使用在 address 项中的 queue 项环绕一个 anycast 配置项。例如:

    <configuration ...>
      <core ...>
        ...
        <address name="my.anycast.destination">
          <anycast>
            <queue name="q1"/>
            <queue name="q2"/>
          </anycast>
        </address>
      </core>
    </configuration>

如果您的配置(如上方所示)在集群中的多个代理间有镜像,集群就可以以不透明于制作者和消费者的方式对点对点进行负载平衡。确切的行为取决于为集群配置消息负载平衡策略。

其他资源

4.4. 为发布订阅消息配置地址

在发布订阅场景中,信息将发送到每个消费者订阅的地址。JMS 主题和 MQTT 订阅是发布-订阅消息的两个示例。为确保与地址接收消息关联的队列以发布与订阅的方式,您为代理配置中的给定 地址 元素定义 多播路由 类型。

当在带有 多播路由 类型的地址上收到消息时,代理会将消息的副本路由到与地址关联的每个队列。要减少复制的开销,每个队列只会发送对消息 的引用,而不是发送到完整副本。

下图显示了 publish-subscribe 消息传递示例。

发布订阅消息传递

以下流程演示了如何为发布订阅消息配置地址。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 向地址添加一个空的 multicast 配置元素。

    <configuration ...>
      <core ...>
        ...
        <address name="my.multicast.destination">
          <multicast/>
        </address>
      </core>
    </configuration>
  3. (可选)将一个或多个 queue 项添加到地址中,并在它们间环绕 multicas 项。通常不需要这一步,因为代理会自动为客户端请求的每个订阅创建一个队列。

    <configuration ...>
      <core ...>
        ...
        <address name="my.multicast.destination">
          <multicast>
            <queue name="client123.my.multicast.destination"/>
            <queue name="client456.my.multicast.destination"/>
          </multicast>
        </address>
      </core>
    </configuration>

4.5. 为点到点和发布-订阅消息传递配置地址

您还可以使用点对点 和发布 订阅语义配置地址。

通常不建议将地址配置为同时使用点到点和发布订阅模式。但是,如果需要,它可能会有用。例如,一个名为 orders 的 JMS 队列,以及名为 order 的 JMS 主题。不同的路由类型使地址似乎因客户端连接而异。在这种情况下,由 JMS 队列生成者发送的消息使用 anycast 路由类型。JMS 主题制作者发送的消息使用 多播路由 类型。当 JMS 主题消费者连接到代理时,它会附加到自己的订阅队列。但是,JMS 队列消费者附加到任何广播 队列

下图展示了点对点以及一起使用的发布-订阅消息示例。

指向并发布订阅消息传递

以下流程演示了如何为点对点和发布订阅消息传递配置地址。

注意

这种情境的行为取决于所使用的协议。对于 JMS,主题和队列制作者与消费者之间有一个明确的区别,这使得逻辑变得非常简单。AMQP 等其他协议并不能实现这种区分。通过 AMQP 发送的消息以 anycastmulticast 路由,消费者默认为 anycast。更多信息请参阅 第 3 章 在网络连接中配置消息协议

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 使用在 address 项中的 queue 项环绕一个 anycast 配置项。例如:

    <configuration ...>
      <core ...>
        ...
        <address name="orders">
          <anycast>
            <queue name="orders"/>
          </anycast>
        </address>
      </core>
    </configuration>
  3. 向地址添加一个空的 multicast 配置元素。

    <configuration ...>
      <core ...>
        ...
        <address name="orders">
          <anycast>
            <queue name="orders"/>
          </anycast>
          <multicast/>
        </address>
      </core>
    </configuration>
    注意

    通常,代理根据需要创建订阅队列,因此无需列出 多播 元素内的特定队列元素。

4.6. 在接受器配置中添加路由类型

通常,如果一个消息由同时使用 anycastmulticast 的地址接收,一个 anycast 队列会接收消息,以及所有 multicast 队列。但是,当连接到地址时,客户端可以指定一个特定的前缀,以指定是否使用 anycastmulticast 连接。前缀是在代理配置的 URL 中使用 anycastPrefixmulticastPrefix 参数来指定的自定义值。

以下流程演示了如何为给定接受器配置前缀。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 对于给定的接收器,若要配置 anycast 前缀,将 anycastPrefix 添加到配置的 URL。设置自定义值。例如:

    <configuration ...>
      <core ...>
        ...
          <acceptors>
             <!-- Acceptor for every supported protocol -->
             <acceptor name="artemis">tcp://0.0.0.0:61616?protocols=AMQP;anycastPrefix=anycast://</acceptor>
          </acceptors>
        ...
      </core>
    </configuration>

    根据前面的配置,acceptor 被配置为使用 anycast://anycast 前缀)。客户端代码可以指定任何cast ://<my.destination >/,如果客户端需要只向 任播 队列之一发送消息。

  3. 对于给定的接受者,若要配置 多播 前缀,请将 multicastPrefix 添加到配置的 URL。设置自定义值。例如:

    <configuration ...>
      <core ...>
        ...
          <acceptors>
             <!-- Acceptor for every supported protocol -->
             <acceptor name="artemis">tcp://0.0.0.0:61616?protocols=AMQP;multicastPrefix=multicast://</acceptor>
          </acceptors>
        ...
      </core>
    </configuration>

    根据上述配置,接收器配置为使用 multicast:// 进行 多播 前缀。如果客户端需要发送到仅多播队列的消息,客户端代码可以指定 multicast://<my.destination & gt;/。

4.7. 配置订阅队列

在大多数情况下,不需要手动创建订阅队列,因为协议经理在第一次请求订阅地址时自动创建订阅队列。如需更多信息,请参阅 第 4.8.3 节 “协议管理器和地址”。对于持久订阅,生成的队列名称通常是客户端 ID 和地址的串联。

以下小节介绍了如何在需要时手动创建订阅队列。

4.7.1. 配置持久的订阅队列

当队列配置为持久订阅时,代理会为任何不活跃订阅者保存消息,并在用户重新连接时将其提供给用户。因此,在订阅队列后,可以保证接收发送到队列的每个消息。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. durable 配置元素添加到所选的队列。设置一个值 true

    <configuration ...>
      <core ...>
        ...
        <address name="my.durable.address">
          <multicast>
            <queue name="q1">
              <durable>true</durable>
            </queue>
          </multicast>
        </address>
      </core>
    </configuration>
    注意

    由于队列默认是持久的,包括 durable 元素并将值设为 true 不是绝对必要,以创建持久队列。但是,明确包含 元素可让您稍后更改队列的行为(如果需要)。

4.7.2. 配置非共享的持久订阅队列

代理可以被配置为防止多个消费者同时连接到队列。因此,通过这种方式配置的队列订阅被视为"非共享"。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. durable 配置元素添加到每个所选队列。设置一个值 true

    <configuration ...>
      <core ...>
        ...
        <address name="my.non.shared.durable.address">
          <multicast>
            <queue name="orders1">
              <durable>true</durable>
            </queue>
            <queue name="orders2">
              <durable>true</durable>
            </queue>
          </multicast>
        </address>
      </core>
    </configuration>
    注意

    由于队列默认是持久的,包括 durable 元素并将值设为 true 不是绝对必要,以创建持久队列。但是,明确包含 元素可让您稍后更改队列的行为(如果需要)。

  3. max-consumers 属性添加到每个所选队列。设置值 1

    <configuration ...>
      <core ...>
        ...
        <address name="my.non.shared.durable.address">
          <multicast>
            <queue name="orders1" max-consumers="1">
              <durable>true</durable>
            </queue>
            <queue name="orders2" max-consumers="1">
              <durable>true</durable>
            </queue>
          </multicast>
        </address>
      </core>
    </configuration>

4.7.3. 配置非可持续的订阅队列

非可持续订阅通常由相关协议管理器管理,它将创建和删除临时队列。

但是,如果您手动创建一个队列,它的行为与不可持续的订阅队列一样,您可以在队列中使用 purge-on-no-consumers 属性。当 purge-on-no-consumers 设为 true 时,队列不会开始接收消息,直到消费者连接为止。另外,当最后一个消费者与队列断开连接时,队列将被清除(即,其消息会被删除)。在新的消费者连接到队列之前,队列不会接收任何其他消息。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. purge-on-no-consumers 属性添加到每个所选队列。设置一个值 true

    <configuration ...>
      <core ...>
        ...
        <address name="my.non.durable.address">
            <multicast>
                <queue name="orders1" purge-on-no-consumers="true"/>
            </multicast>
        </address>
      </core>
    </configuration>

4.8. 自动创建和删除地址和队列

您可以将代理配置为自动创建地址和队列,并在不再使用后删除它们。这样,在客户端可以连接到前,您可以预先配置每个地址。

4.8.1. 自动队列创建和删除的配置选项

下表列出了在配置 address-setting 元素以自动创建和删除队列和地址时可用的配置元素。

如果您希望 address-setting 到…​添加这个配置…​

当客户端发送消息到或试图使用来自映射到不存在的地址的队列的消息时,创建地址。

auto-create-addresses

当客户端发送消息到或试图使用来自队列的消息时,创建队列。

auto-create-queues

当它不再有任何队列时,删除自动创建的地址。

auto-delete-addresses

当队列有 0 个消费者和 0 消息时,删除自动创建的队列。

auto-delete-queues

如果客户端没有指定,使用一个特定的路由类型。

default-address-routing-type

4.8.2. 配置自动创建和删除地址和队列

以下流程演示了如何配置自动创建和删除地址和队列。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 配置 address-setting 以自动创建和删除。以下示例使用了上表中提到的所有配置元素。

    <configuration ...>
     <core ...>
      ...
      <address-settings>
        <address-setting match="activemq.#">
          <auto-create-addresses>true</auto-create-addresses>
          <auto-delete-addresses>true</auto-delete-addresses>
          <auto-create-queues>true</auto-create-queues>
          <auto-delete-queues>true</auto-delete-queues>
          <default-address-routing-type>ANYCAST</default-address-routing-type>
        </address-setting>
      </address-settings>
      ...
     </core>
    </configuration>
    address-setting
    address-setting 元素的配置应用于与通配符地址 activemq.# 匹配的任何地址或队列。
    auto-create-addresses
    当客户端请求连接到尚不存在的地址时,代理会创建地址。
    auto-delete-addresses
    当它不再有与之关联的队列时,自动删除自动创建的地址。
    auto-create-queues
    当客户端请求连接到尚不存在的队列时,代理会创建队列。
    auto-delete-queues
    当不再有使用者或消息时,自动创建的队列会被删除。
    default-address-routing-type
    如果客户端在连接时没有指定路由类型,代理会在将消息发送到地址时使用 ANYCAST。默认值为 MULTICAST

其他资源

4.8.3. 协议管理器和地址

称为 协议管理器 的组件会将协议相关的概念映射到 AMQ Broker 地址模型中使用的概念;队列和路由类型。在某些情况下,协议管理器可能会在代理中自动创建队列。

例如,当客户端发送带有地址 /house/room1/lights/house/room2/lights 的问题时,CNO 协议管理器了解这两个地址需要 多播 语义。因此,协议管理器首先会查找确保为这两个地址启用 多播。如果没有,它会尝试动态创建它们。如果成功,协议经理会为客户端请求的每个订阅创建特殊订阅队列。

每个协议都的行为稍有不同。下表介绍了在请求将帧订阅到各种 队列时 通常会发生的情况。

如果队列为这个类型…​协议管理器的典型操作是…​

Durable 订阅队列

查找适当的地址并确保启用了 多播 语义。然后,它会创建一个带有客户端 ID 的特殊订阅队列,其地址作为其名称,而 多播 作为其路由类型。

特殊名称允许协议管理器快速识别所需的客户端订阅队列,客户端应在稍后断开连接并重新连接。

当客户端取消订阅队列时。

临时订阅队列

查找适当的地址并确保启用了 多播 语义。然后,它会在此地址下创建一个带有随机(读取 UUID)名称的队列,并带有 多播路由 类型。

客户端断开与队列的连接后,将删除。

点到点队列

查找适当的地址并确保启用 任何 广播路由类型。如果是,它旨在查找名称与地址相同的队列。如果不存在,它会查找第一个可用队列。然后它不存在,它会自动创建队列(启用自动创建)。队列消费者绑定到此队列。

如果队列是自动创建的,则在没有使用者且其中没有消息时自动删除它。

4.9. 指定完全限定的队列名称

在内部,代理将客户端的请求映射到特定队列。代理决定代表将消息发送到的队列,或者从哪个队列接收消息的队列。但是,更高级的用例可能需要客户端直接指定队列名称。在这些情况下,客户端可以使用 完全限定的队列名称 (FQQN)。FQQN 包括地址名称和队列名称,用 :: 分隔。

以下流程演示了如何在连接到具有多个队列的地址时指定 FQQN。

先决条件

  • 您已经配置了两个或更多队列的地址,如下例所示。

    <configuration ...>
      <core ...>
        ...
        <addresses>
           <address name="my.address">
              <anycast>
                 <queue name="q1" />
                 <queue name="q2" />
              </anycast>
           </address>
        </addresses>
      </core>
    </configuration>

流程

  • 在客户端代码中,在从代理请求连接时使用地址名称和队列名称。使用两个冒号: :: 来分隔名称。例如:

    String FQQN = "my.address::q1";
    Queue q1 session.createQueue(FQQN);
    MessageConsumer consumer = session.createConsumer(q1);

4.10. 配置分片队列

用于在队列间处理消息的常见模式,其中只需要部分排序是使用 队列分片。这意味着您可以定义一个作为单一逻辑队列的 anycast 地址,但它由多个底层物理队列支持。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 添加一个 address 元素并设置 name 属性。例如:

    <configuration ...>
      <core ...>
        ...
        <addresses>
           <address name="my.sharded.address"></address>
        </addresses>
      </core>
    </configuration>
  3. 添加 anycast 路由类型,并包含所需的分片队列数。在以下示例中,队列 q1, q2, 和 q3 添加为 anycast 的目的地。

    <configuration ...>
      <core ...>
        ...
        <addresses>
           <address name="my.sharded.address">
              <anycast>
                 <queue name="q1" />
                 <queue name="q2" />
                 <queue name="q3" />
              </anycast>
           </address>
        </addresses>
    </core>
    </configuration>

根据上述配置,发送到 my.sharded.address 的消息会在 q1, q2q3 之间均匀分布。在使用完全限定域名(FQQN)时,客户端可以直接连接到特定的物理队列。并接收仅发送到该特定队列的消息。

要将特定消息绑定到特定队列,客户端可以为每条消息指定消息的消息。代理将分组的消息路由到同一队列,另一个消费者全部处理它们。

其他资源

4.11. 配置最后的值队列

最后一个值队列 是队列类型,当将具有相同值值的新消息放入队列中时,丢弃队列中的消息。通过此行为,最后一个值队列只保留同一键的信息的最后值。

最后一个值队列的一个简单用例是监控库存费用,只有特定库存的最新价值就是值得关注。

注意

如果没有配置的最后值键的消息发送到最后一个值队列,则代理会将此消息作为"常规"消息处理。当有配置的最后值键到达的新消息时,这些消息不会从队列清除。

您可以单独配置最后一个值队列,或者配置与一组地址关联的所有队列。

以下流程演示了如何使用以下方法配置最后一个值队列。

4.11.1. 单独配置最后一个值队列

以下流程演示了如何单独配置最后一个值队列。

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 对于给定队列,添加 last-value-key 键并指定自定义值。例如:

    <address name="my.address">
        <multicast>
            <queue name="prices1" last-value-key="stock_ticker"/>
        </multicast>
    </address>
  3. 另外,您可以配置最后一个值队列,该队列使用默认值 _AMQ_LVQ_NAME。为此,请将 last-value 键添加到给定队列。将值设为 true。例如:

    <address name="my.address">
        <multicast>
            <queue name="prices1" last-value="true"/>
        </multicast>
    </address>

4.11.2. 为地址配置最后一个值队列

以下流程演示了如何为地址 或一组 地址配置最后一个值队列。

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. address-setting 元素中,为匹配的地址添加 default-last-value-key。指定一个自定义值。例如:

    <address-setting match="lastValue">
       <default-last-value-key>stock_ticker</default-last-value-key>
    </address-setting>

    根据上述配置,与 lastValue 地址关联的所有队列都使用 stock_ticker 的最后一个值。默认情况下不设置 default-last-value-key 的值。

  3. 要为 一组 地址配置最后的值队列,您可以指定地址通配符。例如:

    <address-setting match="lastValue.*">
       <default-last-value-key>stock_ticker</default-last-value-key>
    </address-setting>
  4. 或者,您可以将所有与地址 或一组 地址关联的队列配置为使用默认值 _AMQ_LVQ_NAME。为此,请添加 default-last-value-queue,而不是 default-last-value-key。将值设为 true。例如:

    <address-setting match="lastValue">
       <default-last-value-queue>true</default-last-value-queue>
    </address-setting>

其他资源

4.11.3. 最后值队列行为示例

本例演示了最后一个值队列的行为。

broker.xml 配置文件中,假设您添加了以下配置:

<address name="my.address">
    <multicast>
        <queue name="prices1" last-value-key="stock_ticker"/>
    </multicast>
</address>

上述配置会创建一个名为 price 1 的队列,其值为 stock_ticker 的最后一个值。

现在,假设客户端会发送两条信息。每个消息在属性 stock_tickerATN 值相同。每个消息在名为 stock_price 的属性中具有不同的值。每个消息都发送到同一队列、价格1

TextMessage message = session.createTextMessage("First message with last value property set");
message.setStringProperty("stock_ticker", "ATN");
message.setStringProperty("stock_price", "36.83");
producer.send(message);
TextMessage message = session.createTextMessage("Second message with last value property set");
message.setStringProperty("stock_ticker", "ATN");
message.setStringProperty("stock_price", "37.02");
producer.send(message);

stock_ticker 最后一个值键的值相同(在此情况下为 ATN)的两条消息到达 price1 队列时,只有最新的消息保留在队列中,第一个被清除的消息。在命令行中输入以下行来验证此行为:

TextMessage messageReceived = (TextMessage)messageConsumer.receive(5000);
System.out.format("Received message: %s\n", messageReceived.getText());

在本例中,您看到的是第二条消息,因为这两个消息对最后一个值键使用相同的值,并在第一个信息之后在队列中收到第二个消息。

4.11.4. 为最后一个值队列强制使用非破坏性

当消费者连接到队列时,通常的行为是发送到该消费者的消息仅由消费者获取。当消费者确认消息收到时,代理会从队列中删除消息。

作为正常消耗的替代选择,您可以将队列配置为强制实施 非破坏性 的消耗。在这种情况下,当队列向消费者发送消息时,其他消费者仍然可以接收该消息。此外,即使消费者使用过它,消息也会保留在队列中。当您强制实施这种非破坏性消耗行为时,消费者被称为队列 浏览器

强制使用非破坏性是最后一个值队列的一个非常有用的配置,因为它可确保队列始终保留一个特定最后一个值值的最新值。

以下流程演示了如何为最后一个值队列强制实施非破坏性消耗。

先决条件

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 如果您之前将队列单独配置为最后一个值队列,请添加 非破坏性 的密钥。将值设为 true。例如:

    <address name="my.address">
       <multicast>
          <queue name="orders1" last-value-key="stock_ticker" non-destructive="true" />
       </multicast>
    </address>
  3. 如果您之前为最后一个值队列配置了地址 或一组 地址,请添加 default-non-destructive 键。将值设为 true。例如:

    <address-setting match="lastValue">
       <default-last-value-key>stock_ticker </default-last-value-key>
       <default-non-destructive>true</default-non-destructive>
    </address-setting>
    注意

    默认情况下,default-non-structive 的值为 false

4.12. 将过期的消息移到到期地址

对于最后一个值队列以外的队列,如果您只有一个非破坏性消费者,则代理永远不会从队列中删除消息,从而导致队列大小增加时间。要防止这种不约束的队列大小增长,您可以配置当消息过期时,并指定代理到达过期消息的地址。

4.12.1. 配置消息到期

以下流程演示了如何配置消息到期。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. core 元素中,设置 message-expiry-scan-period 以指定代理扫描过期信息的频率。

    <configuration ...>
       <core ...>
          ...
          <message-expiry-scan-period>1000</message-expiry-scan-period>
          ...

    根据上述配置,代理每 1000 毫秒扫描过期的消息的队列。

  3. 在匹配地址 或一组 地址的 address-setting 元素中,指定到期地址。另外,设置消息过期时间。例如:

    <configuration ...>
       <core ...>
          ...
          <address-settings>
             ...
             <address-setting match="stocks">
                ...
                <expiry-address>ExpiryAddress</expiry-address>
                <expiry-delay>10</expiry-delay>
                ...
             </address-setting>
             ...
          <address-settings>
    <configuration ...>
    expiry-address
    匹配地址或地址的到期地址。在上例中,代理将 库存地址的过期消息发送到名为 ExpiryAddress 的到期地址。
    expiry-delay

    过期时间(以毫秒为单位),代理适用于 使用默认 过期时间的消息。默认情况下,消息的过期时间为 0, 表示它们不会过期。对于过期时间大于默认值的消息,expiry-delay 没有影响。

    例如,假设您将地址上的 expiry-delay 设置为 10,如上例中所示。如果名为 0 的默认过期时间的消息到达这个地址的队列,则代理会将消息的过期时间从 0 改为 10。但是,如果另一条消息使用 20 过期时间,则其过期时间将不会改变。如果将 expiry-delay 设置为 -1,则禁用了此功能。默认情况下,expiry-delay 设置为 -1

  4. 另外,您还可以为 expiry-delay 指定值,而是指定最小和最大到期延迟值。例如:

    <configuration ...>
       <core ...>
          ...
          <address-settings>
             ...
             <address-setting match="stocks">
                ...
                <expiry-address>ExpiryAddress</expiry-address>
                <min-expiry-delay>10</min-expiry-delay>
                <max-expiry-delay>100</max-expiry-delay>
                ...
             </address-setting>
             ...
          <address-settings>
    <configuration ...>
    min-expiry-delay
    代理适用于消息的最低过期时间(以毫秒为单位)。
    max-expiry-delay

    代理应用到消息的最大过期时间(以毫秒为单位)。

    代理应用 min-expiry-delaymax-expiry-delay 的值,如下所示:

    • 对于默认到期时间 0 的消息,代理会将到期时间设置为 max-expiry-delay 的指定的值。如果您没有为 max-expiry-delay 指定值,则代理会将到期时间设置为 min-expiry-delay 指定的值。如果您还没有为 min-expiry-delay 指定一个值,代理不会更改消息的过期时间。
    • 对于在 max-expiry-delay 的值上方具有过期时间的消息,代理会将到期时间设置为 max-expiry-delay 的指定的值。
    • 对于在 min-expiry-delay 的值下具有过期时间的消息,代理会将到期时间设置为 min-expiry-delay 指定的值。
    • 对于在 min-expiry-delaymax-expiry-delay 的值之间过期的消息,代理不会更改消息的过期时间。
    • 如果您为 expiry-delay 指定一个值(即,默认值 -1以外的默认值),这将覆盖您为 min-expiry-delaymax-expiry-delay 指定的值。
    • min-expiry-delaymax-expiry-delay 的默认值是 -1( 禁用)。
  5. 配置文件的 address 元素中,配置之前为 expiry-address 指定的地址。在此地址定义队列。例如:

    <addresses>
        ...
        <address name="ExpiryAddress">
            <anycast>
                <queue name="ExpiryQueue"/>
            </anycast>
        </address>
        ...
    </addresses>

    前面的示例配置将到期队列 ExpiryQueue 与到期地址 ExpiryAddress 关联。

4.12.2. 自动创建到期资源

常见的用例是根据原始地址隔离过期的消息。例如,您可以选择将过期的消息从名为来自名为 stocks 的地址路由到一个名为 EXP.stocks 的过期队列。同样,您可以将过期的消息从名为 order 的地址路由到名为 EXP.orders 的过期队列。

这种路由模式有助于轻松跟踪、检查和管理过期的消息。但是,很难在主要使用自动创建的地址和队列的环境中实现这种模式。在这种环境中,管理员不希望额外的工作手动创建地址和队列来容纳过期的消息。

作为解决方案,您可以将代理配置为自动创建资源(即地址和队列)以处理给定地址 或一组 地址的过期消息。以下流程演示了示例。

先决条件

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 找到您之前添加到配置文件的 <address-setting > 元素,以定义匹配地址 或一组 地址的到期地址。例如:

    <configuration ...>
    
       <core ...>
          ...
          <address-settings>
             ...
             <address-setting match="stocks">
                ...
                <expiry-address>ExpiryAddress</expiry-address>
                ...
             </address-setting>
             ...
          <address-settings>
    <configuration ...>
  3. <address-setting > 元素中,添加配置项来指示代理自动创建到期资源(即地址和队列),以及如何命名这些资源。例如:

    <configuration ...>
       <core ...>
          ...
          <address-settings>
             ...
             <address-setting match="stocks">
                ...
                <expiry-address>ExpiryAddress</expiry-address>
                <auto-create-expiry-resources>true</auto-create-expiry-resources>
                <expiry-queue-prefix>EXP.</expiry-queue-prefix>
                <expiry-queue-suffix></expiry-queue-suffix>
                ...
             </address-setting>
             ...
          <address-settings>
    <configuration ...>
    auto-create-expiry-resources

    指定代理是否自动创建到期地址和队列来接收过期的消息。默认值为 false

    如果参数值设为 true,代理会自动创建一个 <address &gt; 元素来定义到期地址和关联的到期队列。自动创建的 <address& gt; 元素的名称值与 指定的值 <expiry-address> 匹配。

    自动创建的过期队列有 multicast 路由类型。默认情况下,代理为到期队列命名,以匹配最初发送过期消息的地址,如 stocks

    代理还会为使用 _AMQ_ORIG_ADDRESS 属性的到期队列定义过滤器。此过滤器确保到期队列只接收发送到对应原始地址的消息。

    expiry-queue-prefix

    代理应用到自动创建到期队列的名称前缀。默认值为 EXP。

    当您定义前缀值或保留默认值时,到期队列的名称是前缀和原始地址的串联,如 EXP.stocks

    expiry-queue-suffix
    代理应用于自动创建到期队列名称的后缀。默认值没有被定义(即代理不会应用后缀)。

您可以使用本身(例如,使用 AMQ Broker Core Protocol JMS 客户端)或使用完全限定的队列名称(例如,使用其他 JMS 客户端时)直接访问到期队列。

注意

由于到期地址和队列是自动创建的,因此与删除自动创建的地址和队列相关的任何地址设置也适用于这些到期资源。

其他资源

4.13. 将未接收的消息移动到死信地址

如果向客户端发送一条消息失败,您可能不希望代理进行持续尝试传递消息。为防止有限发送尝试,您可以定义 死信地址,以及一个或多个 asscociated dead letter Queue。在指定的发送尝试次数后,代理会从其原始队列中删除未发送的消息,并将消息发送到配置的死信地址。系统管理员可以在以后消耗来自死信队列的未发送的消息来检查消息。

如果您没有为给定队列配置死信地址,代理会在指定数量的传输尝试后永久从队列中删除未接收的消息。

从死信队列消耗的消息取消接收以下属性:

_AMQ_ORIG_ADDRESS
指定消息的原始地址的字符串属性
_AMQ_ORIG_QUEUE
指定消息的原始队列的字符串属性

4.13.1. 配置死信地址

以下步骤演示了如何配置死信地址和关联的死信队列。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 在与队列名称匹配的 < address-setting > 元素中,为死信地址名称设置值以及传输尝试的最大数量。例如:

    <configuration ...>
       <core ...>
          ...
          <address-settings>
             ...
             <address-setting match="exampleQueue">
                <dead-letter-address>DLA</dead-letter-address>
                <max-delivery-attempts>3</max-delivery-attempts>
             </address-setting>
          ...
          <address-settings>
    <configuration ...>
    匹配
    代理在此 address-setting 部分中应用配置的地址。您可以为 < address-setting > 元素的 match 属性指定一个通配符表达式。如果要将 < address-setting > 元素中配置的死信>元素 与一组 匹配的地址关联,可使用通配符表达式。
    dead-letter-address
    死信地址的名称。在本例中,代理将来自队列 示例Queue 的消息移到 dead letter 地址 DLA
    max-delivery-attempts
    代理在将未发送的消息移动到配置的死信地址之前,代理进行的最大交付尝试数。在本例中,代理会在 3 次失败发送尝试后将未发送的消息移到死信地址。默认值为 10。如果您希望代理进行无限次重新发送尝试,请指定 -1 值。
  3. address 部分中,为死信 地址 DLA 添加地址元素。要将死信队列与死信地址关联,请为 队列 指定 name 值。例如:

    <configuration ...>
       <core ...>
          ...
          <addresses>
             <address name="DLA">
                <anycast>
                   <queue name="DLQ" />
                </anycast>
             </address>
          ...
          </addresses>
       </core>
    </configuration>

在上述配置中,您要将名为 DLQ 的死信队列与死信地址 DLA 关联。

其他资源

4.13.2. 自动创建死信队列

常见的用例是根据原始地址隔离未传输的消息。例如,您可以选择将名为 stocks 的地址的未传输消息路由到名为 DLA.stocks 的死信队列,该队列名为 DLQ.stocks。同样,您可以将未发送的消息从名为 orders 的地址路由到一个名为 DLA.orders的死信地址。

这种路由模式有助于轻松跟踪、检查和管理实时消息。但是,很难在主要使用自动创建的地址和队列的环境中实现这种模式。这种类型的环境的系统管理员可能不希望进行手动创建地址和队列所需的额外工作来保存未发送的消息。

作为解决方案,您可以将代理配置为自动创建寻址和队列来处理未传输的消息,如以下步骤所示。

先决条件

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 找到您之前添加的 &lt ;address-setting > 元素,以定义匹配队列或一组队列的死信地址。例如:

    <configuration ...>
       <core ...>
          ...
          <address-settings>
             ...
             <address-setting match="exampleQueue">
                <dead-letter-address>DLA</dead-letter-address>
                <max-delivery-attempts>3</max-delivery-attempts>
             </address-setting>
          ...
          <address-settings>
    <configuration ...>
  3. <address-setting > 元素中,添加配置项来指示代理自动创建死信资源(即地址和队列),以及如何命名这些资源。例如:

    <configuration ...>
       <core ...>
          ...
          <address-settings>
             ...
             <address-setting match="exampleQueue">
                <dead-letter-address>DLA</dead-letter-address>
                <max-delivery-attempts>3</max-delivery-attempts>
                <auto-create-dead-letter-resources>true</auto-create-dead-letter-resources>
                <dead-letter-queue-prefix>DLQ.</dead-letter-queue-prefix>
                <dead-letter-queue-suffix></dead-letter-queue-suffix>
             </address-setting>
          ...
          <address-settings>
    <configuration ...>
    auto-create-dead-letter-resources

    指定代理是否自动创建死信地址和队列来接收未传输的消息。默认值为 false

    如果将 auto-create-dead-letter-resources 设为 true,则代理会自动创建一个 & lt;address > 元素来定义死信地址和关联的死信队列。自动创建的 < address> 元素的名称与您为 < dead-letter-address> 指定的名称值匹配

    代理在自动创建的 <address> 元素 中定义的 死信队列具有 多播路由 类型。默认情况下,代理将死信队列名称以匹配未发送的消息的原始地址,如 stocks

    代理还会为使用 _AMQ_ORIG_ADDRESS 属性的死信队列定义过滤器。此过滤器确保死信队列仅接收发送到对应原始地址的消息。

    dead-letter-queue-prefix

    代理应用到自动创建死信队列的名称前缀。默认值为 DLQ。

    当您定义前缀值或保留默认值时,死信队列的名称是前缀的串联和原始地址,如 DLQ.stocks

    dead-letter-queue-suffix
    代理应用到自动创建的死信队列的后缀。默认值没有被定义(即代理不会应用后缀)。

4.14. 过期或未发送的 AMQP 信息上的注解和属性

在代理移动过期或未发送的 AMQP 消息前,到您配置的过期或死信队列,代理会将注解和属性应用到消息。客户端可以根据这些属性或注解创建过滤器,以从到期或死信队列中选择使用的特定消息。

注意

代理适用的属性是 内部 属性,这些属性不会暴露给客户端供常规使用,但 可由 过滤器中的客户端指定。

下表显示了代理适用于过期或未发送的 AMQP 消息的注解和内部属性。

注解名称内部属性名称描述

x-opt-ORIG-MESSAGE-ID

_AMQ_ORIG_MESSAGE_ID

原始消息 ID,在消息移到到期或死信队列之前。

x-opt-ACTUAL-EXPIRY

_AMQ_ACTUAL_EXPIRY

消息到期时间,指定为自上 epoch 开始的毫秒数。

x-opt-ORIG-QUEUE

_AMQ_ORIG_QUEUE

已过期或未发送的消息的原始队列名称。

x-opt-ORIG-ADDRESS

_AMQ_ORIG_ADDRESS

过期或未发送的消息的原始地址名称。

其他资源

4.15. 禁用队列

如果您在代理配置中手动定义队列,则队列会被默认启用。

但是,在有些情况下,您要定义队列以便客户端可以订阅该队列,但无法为消息路由使用队列。或者,在有些情况下,您可能想要停止消息流到队列,但仍保持客户端绑定到队列。在这些情况下,您可以禁用队列。

以下示例演示了如何禁用您在代理配置中定义的队列。

先决条件

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 对于您之前定义的队列,添加 enabled 属性。要禁用队列,请将此属性的值设为 false。例如:

    <addresses>
       <address name="orders">
          <multicast>
             <queue name="orders" enabled="false"/>
          </multicast>
       </address>
    </addresses>

    enabled 属性的默认值为 true。当您将值设为 false 时,到队列的消息路由将被禁用。

注意

如果您在地址中 禁用所有 队列,发送到该地址的任何信息都会被静默丢弃。

4.16. 限制连接到队列的用户数量

使用 max-consumers 属性限制连接到特定队列的用户数量。通过将 max-consumers 标志设置为 1 来创建独占消费者的使用者。默认值为 -1,它设定无限数量的用户。

以下流程演示了如何对可连接到队列的用户数量设置限制。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 对于给定队列,添加 max-consumers 键并设置一个值。

    <configuration ...>
      <core ...>
        ...
        <addresses>
           <address name="foo">
              <anycast>
                 <queue name="q3" max-consumers="20"/>
              </anycast>
           </address>
        </addresses>
      </core>
    </configuration>

    根据上述配置,只有 20 个消费者可以同时连接到队列 q3

  3. 若要创建独占消费者,将 max-consumers 设为 1

    <configuration ...>
      <core ...>
        ...
        <address name="foo">
          <anycast>
            <queue name="q3" max-consumers="1"/>
          </anycast>
        </address>
      </core>
    </configuration>
  4. 要允许无限数量的消费者,将 max-consumers 设置为 -1

    <configuration ...>
      <core ...>
        ...
        <address name="foo">
          <anycast>
             <queue name="q3" max-consumers="-1"/>
          </anycast>
        </address>
      </core>
    </configuration>

4.17. 配置专用队列

专用队列是特殊队列,将所有消息都仅路由到一个使用者。当您希望所有消息被同一消费者以串行方式处理时,此配置很有用。如果有多个消费者用于队列,则只有一个消费者接收消息。如果该使用者从队列断开连接,则会选择另一个消费者。

4.17.1. 单独配置专用队列

以下流程演示了如何单独将给定队列配置为独占。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 对于给定的队列,添加 专用 密钥。将值设为 true

    <configuration ...>
      <core ...>
        ...
        <address name="my.address">
          <multicast>
            <queue name="orders1" exclusive="true"/>
          </multicast>
        </address>
      </core>
    </configuration>

4.17.2. 为地址配置专用队列

以下步骤演示了如何配置地址 或一组 地址,以便所有关联的队列都是独占的。

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. address-setting 元素中,对于匹配的地址,添加 default-exclusive-queue 键。将值设为 true

    <address-setting match="myAddress">
        <default-exclusive-queue>true</default-exclusive-queue>
    </address-setting>

    根据上述配置,与 myAddress 地址关联的所有队列都是独占的。默认情况下,default-exclusive-queue 的值为 false

  3. 要为 一组 地址配置专用队列,您可以指定地址通配符。例如:

    <address-setting match="myAddress.*">
        <default-exclusive-queue>true</default-exclusive-queue>
    </address-setting>

其他资源

4.18. 将特定的地址设置应用到临时队列

使用 JMS 时,代理通过将通用唯一标识符(UUID)分配为地址名称和队列名称来创建 临时队列

默认的 & lt;address-setting match="#" > 将配置的地址设置应用到 所有 队列,包括临时对象。如果您只想将特定的地址设置应用到临时队列,您可以选择指定临时( temporary-queue-namespace ),如下所述。然后您可以指定与命名空间匹配的地址设置,代理会将这些设置应用到所有临时队列。

创建临时队列并且存在临时队列命名空间时,代理会将 temporary-queue-namespace 值和配置的分隔符(默认 .)添加到地址名称。它使用 来引用匹配的地址设置。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 添加 temporary-queue-namespace 值。例如:

    <temporary-queue-namespace>temp-example</temporary-queue-namespace>
  3. 添加一个 address-setting 元素,其 match 值与临时队列命名空间对应。例如:

    <address-settings>
       <address-setting match="temp-example.#">
          <enable-metrics>false</enable-metrics>
       </address-setting>
    </address-settings>

    这个示例禁用代理创建的所有临时队列中的指标。

    注意

    指定临时队列命名空间不会影响临时队列。例如,命名空间不会更改临时队列的名称。命名空间用于引用临时队列。

其他资源

4.19. 配置环队列

通常,AMQ Broker 中的队列使用 first-in 和 first-out(FIFO)语法。这意味着代理将信息添加到队列的尾部,并将它们从头中删除。环队列是存放指定、固定消息数量的特殊队列。当新消息到达但队列已包含指定数量的消息时,代理通过删除队列头条来维护固定队列大小。

例如,假设配置了大小为 3 的环队列,以及按顺序发送消息 ABCD 的生产者。当消息 C 到达队列时,队列中的消息数量已到达配置的环大小。此时,消息 A 位于队列的头部,而消息 C 则位于尾部。当消息 D 到达队列时,代理会将消息添加到队列的尾部。为保持固定队列大小,代理会删除队列的头部(即消息 A)上的消息。Message B 现在位于队列的头部。

4.19.1. 配置环队列

以下步骤演示了如何配置环队列。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 要在未设置显式环大小的匹配地址上定义所有队列的默认环大小,请在 address-setting 元素中指定 default-ring-size 的值。例如:

    <address-settings>
       <address-setting match="ring.#">
          <default-ring-size>3</default-ring-size>
       </address-setting>
    </address-settings>

    default-ring-size 参数对于定义自动创建队列的默认大小特别有用。default-ring-size 的默认值为 -1( 即无大小限制)。

  3. 要在特定队列上定义环大小,请将 ring-size 键添加到 queue 元素。指定一个值。例如:

    <addresses>
       <address name="myRing">
          <anycast>
             <queue name="myRing" ring-size="5" />
          </anycast>
       </address>
    </addresses>
注意

您可以在代理运行时更新 ring-size 的值。代理会动态应用更新。如果新 ring-size 值低于前一个值,则代理不会立即从队列的头中删除信息来强制新大小。发送到队列的新消息仍强制删除旧消息,但队列不会达到新的、减小大小,直到客户端正常使用消息。

4.19.2. 环队列故障排除

本节描述了环队列的行为与其配置不同的情况。

交付消息和回滚

当消息传送给消费者时,该消息处于"不同"状态,其中邮件不再位于队列中,但尚未确认。消息会一直处于发送状态,直到消费者确认。处于非托管状态的消息无法从环队列中删除。

由于代理无法删除交付消息,客户端可以将更多消息发送到环队列,而不是环大小配置似乎允许。例如,考虑这种情况:

  1. producer 将三个消息发送到配置了 ring-size="3" 的环队列。
  2. 所有消息会立即分配给消费者。

    此时,Message Count= 3 和 deliver Count= 3

  3. producer 将另一条消息发送到队列。然后,消息被分配到消费者。

    现在,messageCount = 4deliverCount = 4。消息计数 4 大于配置的环大小 3。但是,代理应该允许这种情况,因为它无法从队列中删除发送的消息。

  4. 现在,假设使用者已经关闭,而不会导致任何消息。

    在这种情况下,发送四个未确认的消息会取消相关的消息,并以相反的顺序重新添加到队列的头端。此操作将队列置于其配置的环大小。由于环队列优先于队列尾部的消息,因此队列丢弃由制作者发送的第一个消息,因为这是向队列头添加的最后一个消息。事务或者核心会话回滚的方式相同。

如果您直接使用核心客户端,或使用 AMQ Core Protocol JMS 客户端,您可以通过减少 consumerWindowSize 参数的值(默认为 1024 * 1024 字节)来最小化传输的消息数量。

调度的消息

当调度的消息发送到队列时,该消息不会立即添加到队列的尾部,如正常消息。相反,代理会在中间缓冲区中保存调度的消息,并根据消息的详细信息将消息调度到队列的头部。但是,调度的消息仍会反映在队列的消息数中。与收发消息一样,此行为可能会显示代理不强制实施环队列大小。例如,考虑这种情况:

  1. at 12:00,制作者将消息 A 发送到配置了 ring-size="3" 的环队列。该消息计划为 12:05。

    此时,messageCount= 1scheduledCount= 1.

  2. at 12:01,制作者将消息 B 发送到同一环队列。

    现在,messageCount= 2scheduledCount= 1

  3. at 12:02,制作者将消息 C 发送到同一环队列。

    现在,messageCount= 3scheduledCount= 1

  4. at 12:03,制作者将消息 D 发送到同一环队列。

    现在,messageCount= 4scheduledCount= 1

    队列的消息计数现在是 4一个大于 配置的环大小 3。但是,已调度的消息尚不在队列上讲而在队列中(即,它属于代理,并计划在队列中放置)。在为期 12:05 的交付时间,代理将消息放在队列的头部。但是,由于环队列已达到其配置大小,因此计划的消息 A 会立即被删除。

页面信息

与在发送中调度的消息和消息类似,页面的消息不会计入代理强制的环队列大小,因为消息实际上是在地址级别页面,而不是队列级别。页面消息并非技术上在队列中,虽然它反映在队列的 messageCount 值中。

建议您不要对带有环队列的地址使用分页。相反,请确保整个地址可以容纳在内存中。或者,将 address-full-policy 参数配置为 DROP, BLOCKFAIL

其他资源

4.20. 配置被动地址

将地址配置为 被动 可以保留发送到该地址的消息,包括当队列还没有绑定到地址时。当队列稍后创建并绑定到地址时,代理会重新主动将消息分发到这些队列。如果地址 配置为恢复,且还没有绑定到队列,则代理会丢弃发送到该地址的消息。

当您配置被动地址时,代理会创建一个类型的队列的内部实例,称为 环队列。环队列是存放指定、固定消息数量的特殊队列。队列到达指定大小后,到达队列的下一消息会强制从队列中最旧的消息。当您配置被动地址时,您可以间接指定内部环队列的大小。默认情况下,内部队列使用 多播路由 类型。

retroactive 地址使用的内部环队列通过管理 API 公开。您可以检查指标并执行其他常见管理操作,如清空队列。环队列还对地址的总内存用量贡献,这会影响消息分页等行为。

以下步骤演示了如何将地址配置为被动。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. address-setting 元素中的 retroactive-message-count 参数指定一个值。您指定的值定义了代理要保留的信息数量。例如:

    <configuration>
      <core>
        ...
        <address-settings>
           <address-setting match="orders">
              <retroactive-message-count>100</retroactive-message-count>
           </address-setting>
        </address-settings>
    ...
      </core>
    </configuration>
    注意

    您可以在代理运行时更新 retroactive-message-count 的值,在 broker.xml 配置文件或管理 API 中。但是,如果您 减少 这个值,则需要一个额外的步骤,因为恢复地址通过环队列实施。减少 ring-size 参数的 ring 队列不会自动从队列中删除消息,以达到新的 ring-size 值。这个行为可防止意外的消息丢失。在这种情况下,您需要使用管理 API 手动减少环队列中的消息数量。

其他资源

4.21. 禁用内部管理的地址和队列的公告信息

默认情况下,AMQ Broker 会在 OpenWire 客户端连接到代理时查看有关地址和队列的公告信息。公告信息发送到代理创建的内部管理的地址。这些地址会出现在与用户部署的地址和队列相同的显示中的 AMQ 管理控制台中。虽然它们提供了有用的信息,但在代理管理大量目的地时,公告信息可能会导致不必要的后果。例如,消息可能会增加内存用量或控制连接资源。另外,AMQ Management Console 在试图显示为发送公告信息而创建的所有地址时,可能会发生冲突。要避免这种情况,您可以使用以下参数来配置代理中的公告信息行为。

supportAdvisory
将这个选项设置为 true,以启用创建公告信息或 false 来禁用它们。默认值为 true
suppressInternalManagementObjects
将此选项设置为 true,将公告信息公开给管理服务,如 JMX registry 和 AMQ 管理控制台,或 false 来不公开它们。默认值为 true

以下流程演示了如何在代理中禁用公告信息。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 对于 OpenWire 连接器,请在配置的 URL 中添加 supportAdvisorysuppressInternalManagementObjects 参数。按照本节前面所述设置值。例如:

    <acceptor name="artemis">tcp://127.0.0.1:61616?protocols=CORE,AMQP,OPENWIRE;supportAdvisory=false;suppressInternalManagementObjects=false</acceptor>

4.22. 定位地址和队列

联合支持在代理间传输信息,而无需在通用集群中使用代理。代理可以是独立的,也可以在单独的集群中。另外,源和目标代理可以在不同的管理域中,这意味着代理可能有不同的配置、用户和安全设置。代理甚至可能使用不同的 AMQ Broker 版本。

例如,联合适合将信息从一个集群可靠地发送到另一个集群。这种传输可能会跨越广域网(WAN)、云基础架构的区域或互联网。如果源代理到目标代理的连接丢失(例如,因为网络故障),源代理会尝试重新建立连接,直到目标代理恢复在线为止。当目标代理恢复在线时,邮件传输会恢复。

管理员可以使用地址和队列策略来管理联合。策略配置可以匹配到特定的地址或队列,或者策略可以包含与一组地址或队列匹配的通配符表达式。因此,联邦可以动态应用,作为队列或地址被添加到匹配集合中,或从匹配的集合中删除。策略 可以包含多个 表达式,其中包括 和/或排除特定地址和队列。另外,多个策略也可以应用到代理或代理集群。

在 AMQ Broker 中,两个主要的联邦选项是 address federationqueue federation。这些选项在后面的部分中描述。

注意

代理可以包括联合 仅限本地组件的配置。也就是说,如果您在代理上配置联合,则不需要联合该代理的所有内容。

4.22.1. 关于地址联合

地址联合(address federation)类似于连接的代理之间的全多播分布模式。例如,发送到 BrokerA 上地址的每个消息都传送到该代理上的每个队列。另外,每个消息都传送到 BrokerB 以及所有附加的队列。

地址联合会动态将代理链接到远程代理中的地址。例如,如果本地代理想要从远程代理上的地址获取信息,则远程地址上会自动创建队列。然后,远程代理上的消息会被消耗到这个队列。最后,消息会复制到本地代理上的对应地址,尽管它们最初直接发布到本地地址。

远程代理不需要重新配置,以允许联合在其上创建地址。但是,本地 代理需要被授予远程地址的权限。

4.22.2. 地址联合的通用拓扑

下面介绍了一些使用地址联邦的拓扑。

对称拓扑

在对称拓扑中,生产者和使用者连接到每个代理。队列及其使用者可接收由任一制作者发布的消息。下面是一个对称拓扑的示例。

图 4.1. 在对称拓扑中的地址联合

对称地址联合

为对称拓扑配置地址联合时,务必要将地址策略的 max-hops 属性值设置为 1。这样可保证 仅复制一次 消息,从而避免复制。如果此属性设置为较大的值,则使用者将接收相同消息的多个副本。

全网格拓扑

全网格拓扑与对称设置类似。三个或更多对称的代理相互联合,从而创建一个完整的网格。在这个设置中,生产者和使用者连接到每个代理。队列及其使用者可接收任何生产者发布的消息。此拓扑示例如下所示。

图 4.2. 在完整网格拓扑中联合地址

全网格地址联合

与对称设置一样,在为全网格拓扑配置地址联合时,务必要将地址策略的 max-hops 属性的值设置为 1。这样可保证 仅复制一次 消息,从而避免复制。

Ring topology

在代理环中,每个联合地址都被上游用于环中另一个地址。此拓扑示例如下所示。

图 4.3. 在环拓扑中联合地址

Ring 地址联合

当您为环拓扑配置联合时,为了避免cyclic 复制,务必要将地址策略的 max-hops 属性设置为 n-1 的值,其中 n 是环中节点的数量。例如,在上面的环拓扑中,max-hops 的值设置为 5。这可确保环中的每个地址都只看到消息 一次

环形拓扑的一个优点是,根据您需要进行的物理连接数量,设置价格较低。但是,这种类型的拓扑的一个缺陷是,如果单个代理失败,整个环都会失败。

fan-out 拓扑

在流畅的拓扑中,单个 master 地址通过联合地址树链接到。发布到 master 地址的任何消息都可以被连接到树中的任何代理都接收。树可以被配置为任何深度。也可以通过在树内重新配置现有代理的情况下扩展树。此拓扑示例如下所示。

图 4.4. 在 fan-out 拓扑中进行地址联合

Fan out 地址联合

当您为 fan-out 拓扑配置联合时,请确保将地址策略的 max-hops 属性设置为 n-1 的值,其中 n 是树中的级别数。例如,在上方显示的 fan-out 拓扑中,max-hops 的值设置为 2。这样可保证树中的每个地址都只看到消息 一次

4.22.3. 支持在地址联合配置中区分绑定

配置地址联合时,您可以在地址策略配置中添加对竞争绑定的支持。添加这个支持可让联合响应分离绑定,为远程代理上的给定地址创建一个联合消费者。

例如,假设地址策略中包含一个名为 test.federation.source 的地址,并且包含另一个名为 test.federation.target 的地址。通常,当一个队列在 test.federation.target 上创建,不会导致创建联邦消费者,因为地址不是地址策略的一部分。但是,如果您创建 divert 绑定,使得 test.federation.source 是源地址,test.federation.target 是转发地址的转发地址,则会在转发地址中创建 durable consumer。源地址仍然必须使用 multicast 路由类型,但目标地址可以使用 multicastanycast

示例用例是将 JMS 主题(多播地址 )重定向到 JMS 队列(任何广播地址 )。这可为不支持 JMS 2.0 和共享订阅的传统消费者上启用对消息的负载平衡。

4.22.4. 为代理集群配置联合

以下部分示例演示了如何配置 独立 本地和远程代理之间的地址和队列联合。对于独立代理(联合配置)的名称以及任何地址和队列策略的名称,在本地和远程代理之间必须是唯一的。

但是,如果您要在 集群中 为代理配置联合,则还有额外的要求。对于集群代理(联合配置)的名称以及该配置中的任何地址和队列策略 的名称必须与该集群中的每个代理都相同

确保同一集群中的代理使用相同的联合配置和地址和队列策略名称,避免消息重复。例如,如果同一集群中的代理 有不同的 联合配置名称,这可能会导致出现多个不同命名的转发队列用于同一地址,从而导致下游用户的消息重复。相反,如果同一集群中的代理 使用相同的 联合配置名称,这实质上会创建复制,集群转发队列与下游用户进行负载平衡。这可避免消息重复。

4.22.5. 配置上游地址联合

以下示例演示了如何配置独立代理之间的上游地址联合。在本例中,您要将一个本地(即 下游)代理联合配置为一些远程(即 上游)代理。

先决条件

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 添加新的 < federations> 元素,其中包含 &lt ;federation> 元素。例如:

    <federations>
      <federation name="eu-north-1" user="federation_username" password="32a10275cf4ab4e9">
      </federation>
    </federations>
    name
    联合配置的名称。在本例中,名称与本地代理的名称对应。
    user
    连接到上游代理的共享用户名。
    password
    连接到上游代理的共享密码。
    注意

    如果远程代理的用户和密码凭证不同,您可以在将代理添加到配置中单独指定凭证。此流程稍后会描述。

  3. federation 元素中添加 < address-policy> 元素。例如:

    <federations>
        <federation name="eu-north-1" user="federation_username" password="32a10275cf4ab4e9">
    
            <address-policy name="news-address-federation" auto-delete="true" auto-delete-delay="300000" auto-delete-message-count="-1" enable-divert-bindings="false" max-hops="1" transformer-ref="news-transformer">
            </address-policy>
    
        </federation>
    </federations>
    name
    地址策略的名称。在代理中配置的所有地址策略都必须有唯一的名称。
    auto-delete
    在地址联合过程中,本地代理会在远程地址动态创建持久队列。auto-delete 属性的值指定在本地代理断开连接后队列是否应该被删除, auto-delete-delayauto-delete-message-count 属性的值也已达到。如果要自动清理动态创建的队列,这是非常有用的选项。如果要防止本地代理长时间在远程代理上构建消息,它也是一个有用的选项。但是,如果您希望消息在连接断开连接时总是为本地代理保留排队,则可以将此选项设置为 false,从而避免在本地代理上丢失消息。
    auto-delete-delay
    本地代理断开连接后,此属性的值指定了在动态创建的远程队列有资格删除前的时间长度(以毫秒为单位)。
    auto-delete-message-count
    断开本地代理后,此属性的值指定在符合该队列条件自动删除前,仍可处于动态创建的远程队列中的最大信息数。
    enable-divert-bindings
    将此属性设置为 true 可按需侦听绑定。如果存在与地址策略所包含地址相匹配的地址的分制绑定,那么任何与分组转发地址匹配的队列绑定将根据需要创建。默认值为 false
    max-hops
    在联合过程中可以进行消息的最大跃点数。特定拓扑需要此属性的特定值。如需了解更多有关这些要求的信息,请参阅 第 4.22.2 节 “地址联合的通用拓扑”
    transformer-ref
    转换器配置的名称。如果要在联合消息传输过程中转换消息,可以添加一个转换器配置。此流程稍后会描述转换器配置。
  4. 在 & lt;address-policy > 元素中,添加 address-matching 模式,以便从地址策略中包含和排除地址。例如:

    <federations>
        <federation name="eu-north-1" user="federation_username" password="32a10275cf4ab4e9">
    
            <address-policy name="news-address-federation" auto-delete="true" auto-delete-delay="300000" auto-delete-message-count="-1" enable-divert-bindings="false" max-hops="1" transformer-ref="news-transformer">
    
                <include address-match="queue.bbc.new" />
                <include address-match="queue.usatoday" />
                <include address-match="queue.news.#" />
    
                <exclude address-match="queue.news.sport.#" />
            </address-policy>
    
        </federation>
    </federations>
    Include
    此元素的 address-match 属性的值指定要包含在地址策略中的地址。您可以指定具体地址,如 queue.bbc.newqueue.usatoday。或者,您可以使用通配符表达式来指定 一组 匹配的地址。在前面的示例中,地址策略还包括以字符串 queue.news 开头的所有 地址名称。
    exclude
    此元素的 address-match 属性的值指定要从地址策略中排除的地址。您可以指定准确的地址名,或使用通配符表达式来指定匹配的地址 。在前面的示例中,地址策略排除以字符串 queue.news.sport 开头的所有 地址名称。
  5. (可选)使用 federation 元素,添加一个 transformer 元素来引用自定义转换器实现。例如:

    <federations>
        <federation name="eu-north-1" user="federation_username" password="32a10275cf4ab4e9">
    
            <address-policy name="news-address-federation" auto-delete="true" auto-delete-delay="300000" auto-delete-message-count="-1" enable-divert-bindings="false" max-hops="1" transformer-ref="news-transformer">
    
                <include address-match="queue.bbc.new" />
                <include address-match="queue.usatoday" />
                <include address-match="queue.news.#" />
    
                <exclude address-match="queue.news.sport.#" />
            </address-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>
    name
    转换器配置的名称。这个名称必须在本地代理中唯一。这是您指定为地址策略的 transformer-ref 属性的值的名称。
    class-name

    实施 org.apache. office.artemis.core.server.transformer.Transformer 接口的用户定义的类名称。

    在传输消息之前,使用 消息调用 transformer 的 transform() 方法。这可让您在整合消息标题或正文前转换它。

    属性
    用于保存用于特定转换器配置的键值对。
  6. 联合 元素内,添加一个或多个 上游 元素。每个 上游 元素都定义了与远程代理的连接,以及应用到该连接的策略。例如:

    <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>
                </static-connectors>
                <policy ref="news-address-federation"/>
            </upstream>
    
            <upstream name="eu-west-1" >
                <static-connectors>
                    <connector-ref>eu-west-connector1</connector-ref>
                </static-connectors>
                <policy ref="news-address-federation"/>
            </upstream>
    
            <address-policy name="news-address-federation" auto-delete="true" auto-delete-delay="300000" auto-delete-message-count="-1" enable-divert-bindings="false" max-hops="1" transformer-ref="news-transformer">
    
                <include address-match="queue.bbc.new" />
                <include address-match="queue.usatoday" />
                <include address-match="queue.news.#" />
    
                <exclude address-match="queue.news.sport.#" />
            </address-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>
    static-connectors
    包含一个 连接器 元素列表,它引用本地代理的 broker.xml 配置文件其他位置中定义的 连接器 元素。连接器定义了用于出站连接的传输(TCP、SSL、HTTP 等)和服务器连接参数(主机、端口等)。此流程的下一步演示了如何添加在 static-connectors 元素中引用的连接器。
    policy-ref
    在应用到上游代理的下游代理上配置的地址策略的名称。

    您可以为 上游 元素指定的附加选项如下所述:

    name
    上游代理配置的名称。在本例中,名称与名为 eu-east-1eu-west-1 的上游代理对应。
    user
    创建到上游代理的连接时使用的用户名。如果没有指定,则使用在 联合 元素配置中指定的共享用户名。
    password
    创建到上游代理的连接时使用的密码。如果没有指定,则使用 联合 元素配置中指定的共享密码。
    call-failover-timeout
    call-timeout 类似,但在故障转移尝试期间使用调用。默认值为 -1,这表示超时被禁用。
    call-timeout
    当联合连接传输阻止调用的数据包时,联合连接会等待一个来自远程代理的回复的时间(以毫秒为单位)。如果这个时间过,连接会抛出异常。默认值为 30000
    check-period
    持续时间(以毫秒为单位),本地代理发送到远程代理的连续"keep-alive"消息,以检查联合连接的运行状况。如果联合连接健康,则远程代理会响应每个 keep-alive 消息。如果连接不健康,当下游代理无法接收来自上游代理的响应时,会使用名为 断路器 的机制来阻止联合消费者。如需更多信息,请参阅 circuit-breaker-timeout 参数的描述。check-period 参数的默认值为 30000
    circuit-breaker-timeout
    下游和上游代理之间的单个连接可能由许多联合队列和地址消费者共享。如果代理间的连接丢失,每个联合消费者可能会尝试同时重新连接。为避免这种情况,称为 断路器 的机制将阻止消费者。当指定的超时值 elapses 时,断路器重新尝试连接。如果成功,则使用者将被取消阻塞。否则,再次应用断路器。
    connection-ttl
    如果联合连接停止从远程代理接收信息,则以毫秒为单位的连接会保持活跃时间。默认值为 60000
    discovery-group-ref
    作为为到上游代理定义静态连接器的替代选择,此元素可用于指定已在 broker.xml 配置文件中其他位置配置的发现组。具体来说,您可以将一个现有的 discovery 组指定为此元素的 discovery-group-name 属性的值。有关发现组的更多信息,请参阅 第 14.1.6 节 “代理发现方法”
    ha
    指定是否为连接到上游代理启用高可用性。如果此参数的值被设置为 true,则本地代理可以连接到上游集群中的任何可用代理,并在实时上游代理关闭时自动故障切换到备份代理。默认值为 false
    initial-connect-attempts
    下游代理要连接到上游代理的初始尝试次数。如果在没有建立连接的情况下达到这个值,则上游代理被视为永久离线。下游代理不再将消息路由到上游代理。默认值为 -1,这表示没有限制。
    max-retry-interval
    当连接到远程代理失败时,后续重新连接尝试之间的最长时间(以毫秒为单位)。默认值为 2000
    reconnect-attempts
    如果连接失败,下游代理会尝试重新连接到上游代理的次数。如果在没有重新建立连接的情况下达到这个值,则上游代理被视为永久离线。下游代理不再将消息路由到上游代理。默认值为 -1,这表示没有限制。
    retry-interval
    如果连接到远程代理失败,则在后续的重新连接尝试之间以毫秒为单位为单位。默认值为 500
    retry-interval-multiplier
    应用于 retry-interval 参数的值的倍数。默认值为:1
    share-connection
    如果为同一代理同时配置了下游和上游连接,那么只要下游和上游配置都将把这个参数的值设置为 true,就可以共享同一连接。默认值为 false
  7. 在本地代理上,将连接器添加到远程代理中。这些是在联合地址配置 的静态连接器 元素中引用的连接器。例如:

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

4.22.6. 配置下游地址联合

以下示例演示了如何为独立代理配置下游地址联合。

借助下游地址联合,您可以在本地代理中添加一个或多个远程代理用来连接到本地代理的本地代理。这种方法的优势在于,您可以在单个代理中保留所有联合配置。这可能是 hub 和spoke 拓扑的一个实用方法,例如:

注意

下游地址联合会反转连接与上游地址配置的方向。因此,当您在配置中添加远程代理时,这些代理被视为 下游 代理。下游代理使用配置中的连接信息重新连接到本地代理,该代理现在被视为上游。当您为远程代理添加配置时,本例中会对此进行说明。

先决条件

流程

  1. 在本地代理中,打开 &lt ;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 添加包括 <federation> 项的 <federations> 项。例如:

    <federations>
        <federation name="eu-north-1" user="federation_username" password="32a10275cf4ab4e9">
        </federation>
    </federations>
  3. 添加地址策略配置。例如:

    <federations>
        ...
        <federation name="eu-north-1" user="federation_username" password="32a10275cf4ab4e9">
    
            <address-policy name="news-address-federation" max-hops="1" auto-delete="true" auto-delete-delay="300000" auto-delete-message-count="-1" transformer-ref="news-transformer">
    
                <include address-match="queue.bbc.new" />
                <include address-match="queue.usatoday" />
                <include address-match="queue.news.#" />
    
                <exclude address-match="queue.news.sport.#" />
            </address-policy>
    
        </federation>
      ...
    </federations>
  4. 如果要在传输前转换消息,请添加转换器配置。例如:

    <federations>
        ...
        <federation name="eu-north-1" user="federation_username" password="32a10275cf4ab4e9">
    
            <address-policy name="news-address-federation" max-hops="1" auto-delete="true" auto-delete-delay="300000" auto-delete-message-count="-1" transformer-ref="news-transformer">
    
                <include address-match="queue.bbc.new" />
                <include address-match="queue.usatoday" />
                <include address-match="queue.news.#" />
    
                <exclude address-match="queue.news.sport.#" />
            </address-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>
  5. 为每个远程代理添加 downstream 项。例如:

    <federations>
        ...
        <federation name="eu-north-1" user="federation_username" password="32a10275cf4ab4e9">
    
            <downstream name="eu-east-1">
                    <static-connectors>
                        <connector-ref>eu-east-connector1</connector-ref>
                    </static-connectors>
                    <transport-connector-ref>netty-connector</transport-connector-ref>
                    <policy ref="news-address-federation"/>
            </downstream>
    
            <downstream name="eu-west-1" >
                    <static-connectors>
                        <connector-ref>eu-west-connector1</connector-ref>
                    </static-connectors>
                    <transport-connector-ref>netty-connector</transport-connector-ref>
                    <policy ref="news-address-federation"/>
            </downstream>
    
            <address-policy name="news-address-federation" max-hops="1" auto-delete="true" auto-delete-delay="300000" auto-delete-message-count="-1" transformer-ref="news-transformer">
                <include address-match="queue.bbc.new" />
                <include address-match="queue.usatoday" />
                <include address-match="queue.news.#" />
    
                <exclude address-match="queue.news.sport.#" />
            </address-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>

    如前面的配置所示,远程代理现在被视为本地代理的下游。下游代理使用配置中的连接信息来回连接本地(即 上游)代理。

  6. 在本地代理上,添加供本地和远程代理使用的连接器和接收器来建立联合连接。例如:

    <connectors>
       <connector name="netty-connector">tcp://localhost:61616</connector>
       <connector name="eu-west-1-connector">tcp://localhost:61616</connector>
       <connector name="eu-east-1-connector">tcp://localhost:61617</connector>
    </connectors>
    
    <acceptors>
       <acceptor name="netty-acceptor">tcp://localhost:61616</acceptor>
    </acceptors>
    连接器名称="netty-connector"
    本地代理发送到远程代理的连接器配置。远程代理使用此配置连接回本地代理。
    连接器名称="eu-west-1-connector", connector name="eu-east-1-connector"
    远程代理的连接器。本地代理使用这些连接器连接到远程代理,并共享远程代理所需的配置来回连接本地代理。
    acceptor name="netty-acceptor"
    与远程代理使用的连接器对应的本地代理中的接受者,以连接至本地代理。

4.22.7. 关于队列联合

队列联合提供了一种方式,可以在其它远程代理的本地代理中平衡单一队列负载。

为实现负载平衡,本地代理从远程队列检索信息,以满足本地消费者对消息的要求。下面是一个示例。

图 4.5. 对称队列联合

对称队列联合

远程队列不需要重新配置,且不必位于同一代理或同一集群中。建立远程链接且联合队列需要的所有配置都在本地代理中。

4.22.7.1. 队列联合的优点

以下是您可能选择配置队列联邦的一些原因。

增加容量
队列联合可以创建在多个代理上分发的"逻辑"队列。这个逻辑分布式队列的容量比单个代理中的一个队列要高。在这个设置中,尽可能多的信息会从最初发布到的代理中消耗。仅当需要负载平衡时,系统才会在联合中移动消息。
部署多区域设置

在多区域设置中,您可能在一个地区或场地处有一个消息制作者,并在另一个地区和消费者中有一个消息制作者。但是,您最好保留本地在特定地区的制作者和消费者连接。在这种情况下,您可以在生产者和消费者所处的每个区域中部署代理,并使用队列联合在区域间移动消息(WAN)。下面是一个示例。

图 4.6. 多区域队列联合

多地区队列联合
安全企业 LAN 和 DMZ 之间的通信

在网络安全中,demilitarized 区域 (DMZ)是一个物理或逻辑子网,其中包含一个企业级的、面向企业的外部服务,通常更大、网络(如互联网)。企业级本地区域网络(LAN)的其余部分在防火墙后保留与这个外部网络隔离。

在 DMZ 中,很多消息制作者位于 DMZ 中,而且安全企业 LAN 中的许多消费者可能并不适合使生产者连接到安全企业 LAN 中的代理。在这种情况下,您可以在 DMZ 中部署一个代理,制作者可以向其中发布消息。然后,企业 LAN 中的代理可以连接到 DMZ 中的代理,并使用联合队列从 DMZ 中的代理接收信息。

4.22.8. 配置上游队列联合

以下示例演示了如何为独立代理配置上游队列联合。在本例中,您要将一个本地(即 下游)代理联合配置为一些远程(即 上游)代理。

先决条件

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 在新的 < federations> 元素中添加 < federation> 元素。例如:

    <federations>
      <federation name="eu-north-1" user="federation_username" password="32a10275cf4ab4e9">
      </federation>
    </federations>
    name
    联合配置的名称。在本例中,名称与下游代理的名称对应。
    user
    连接到上游代理的共享用户名。
    password
    连接到上游代理的共享密码。
    注意
    • 如果上游代理的用户和密码凭证不同,您可以在将代理添加到配置中单独指定凭证。此流程稍后会描述。
  3. federation 元素中添加 < queue-policy> 元素。指定 < queue-policy& gt; 元素的属性值。例如:

    <federations>
        <federation name="eu-north-1" user="federation_username" password="32a10275cf4ab4e9">
    
            <queue-policy name="news-queue-federation" include-federated="true" priority-adjustment="-5" transformer-ref="news-transformer">
            </queue-policy>
    
        </federation>
    </federations>
    name
    队列策略的名称。在代理中配置的所有队列策略都必须有唯一的名称。
    包含反馈

    当此属性的值设置为 false 时,配置不会重新处理一个被破坏的消费者(即联合队列上的使用者)。这可避免在对称或闭环拓扑中出现的情况,没有对消费者造成不必要的影响,且系统无法无害的消息流。

    如果您没有 闭环拓扑,可以将此属性的值设置为 true。例如,假设您有以下三个代理、BrokerABrokerBBrokerC 链,且由 BrokerA 的制作者以及 BrokerC 的消费者。在这种情况下,您希望 BrokerB 重新联邦消费者到 BrokerA

    优先级覆盖
    当消费者连接到队列时,当创建上游(即 联合)消费者时,会使用其优先级。联合消费者的优先级由 priority-adjustment 属性的值调整。这个属性的默认值为 -1,它可确保本地使用者在负载平衡期间得到的优先级高于联合消费者。但是,您可以根据需要更改优先级调整的值。
注意

如果只为本地消费者提供优先权,联邦消费者使用消息的速度导致太多消息被移到联邦消费者,但您可以限制联邦消费者消耗消息的速率。要限制消息消耗率,请在联邦用户的客户端连接 URI 中配置 consumerMaxRate 流控制选项。如需更多信息,请参阅使用 AMQ 核心协议 JMS 客户端 文档中的 流控制选项

transformer-ref

转换器配置的名称。如果要在联合消息传输过程中转换消息,可以添加一个转换器配置。此流程稍后会描述转换器配置。

  1. 在 & lt;queue-policy > 元素中,添加 address-matching 模式,以便从队列策略中包含和排除地址。例如:

    <federations>
        <federation name="eu-north-1" user="federation_username" password="32a10275cf4ab4e9">
    
            <queue-policy name="news-queue-federation" include-federated="true" priority-adjustment="-5" 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>
    
        </federation>
    </federations>
Include

此元素的 address-match 属性的值指定要包含在队列策略中的地址。您可以指定具体地址,如 queue.bbc.newqueue.usatoday。或者,您可以使用通配符表达式来指定 一组 匹配的地址。在前面的示例中,队列策略还包括以字符串 queue.news 开头的所有 地址名称。

在与 address-match 属性结合使用,您可以使用 queue-match 属性在队列策略中包含特定队列。与 address-match 属性类似,您可以指定准确的队列名称,也可以使用通配符表达式来指定 一组 队列。在前面的示例中,数字符号(#)通配符表示在每个地址或一组地址上都 包括所有 队列。

exclude

此元素的 address-match 属性的值指定要从队列策略中排除的地址。您可以指定一个精确的地址或使用通配符表达式来指定 一组 匹配的地址。在前面的示例中,数字符号(#)通配符表示排除任何匹配跨越 所有地址中的 queue-match 属性的队列。在这种情况下,任何以字符串 .local 结尾的队列都会被排除。这表示某些队列保留为本地队列,而不是联合。

  1. federation 元素中,添加一个 transformer 元素来引用自定义转换器实现。例如:

    <federations>
        <federation name="eu-north-1" user="federation_username" password="32a10275cf4ab4e9">
    
            <queue-policy name="news-queue-federation" include-federated="true" priority-adjustment="-5" 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>
name
转换器配置的名称。这个名称必须在有问题的代理中唯一。您可以将这个名称指定为地址策略的 transformer-ref 属性的值。
class-name

实施 org.apache. office.artemis.core.server.transformer.Transformer 接口的用户定义的类名称。

在传输消息之前,使用 消息调用 transformer 的 transform() 方法。这可让您在整合消息标题或正文前转换它。

属性

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

  1. 联合 元素内,添加一个或多个 上游 元素。每个 上游 元素都定义了一个上游代理连接,以及应用到该连接的策略。例如:

    <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>
                </static-connectors>
                <policy ref="news-queue-federation"/>
            </upstream>
    
            <upstream name="eu-west-1" >
                <static-connectors>
                    <connector-ref>eu-west-connector1</connector-ref>
                </static-connectors>
                <policy ref="news-queue-federation"/>
            </upstream>
    
            <queue-policy name="news-queue-federation" include-federated="true" priority-adjustment="-5" 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>
    static-connectors
    包含一个 连接器 元素列表,它引用本地代理的 broker.xml 配置文件其他位置中定义的 连接器 元素。连接器定义了用于出站连接的传输(TCP、SSL、HTTP 等)和服务器连接参数(主机、端口等)。以下步骤演示了如何添加联合队列配置的 static-connector 元素引用的连接器。
    policy-ref
    在应用到上游代理的下游代理上配置的队列策略的名称。

    您可以为 上游 元素指定的附加选项如下所述:

name
上游代理配置的名称。在本例中,名称与名为 eu-east-1eu-west-1 的上游代理对应。
user
创建到上游代理的连接时使用的用户名。如果没有指定,则使用在 联合 元素配置中指定的共享用户名。
password
创建到上游代理的连接时使用的密码。如果没有指定,则使用 联合 元素配置中指定的共享密码。
call-failover-timeout
call-timeout 类似,但在故障转移尝试期间使用调用。默认值为 -1,这表示超时被禁用。
call-timeout
当联合连接传输阻止调用的数据包时,联合连接会等待一个来自远程代理的回复的时间(以毫秒为单位)。如果这个时间过,连接会抛出异常。默认值为 30000
check-period
持续时间(以毫秒为单位),本地代理发送到远程代理的连续"keep-alive"消息,以检查联合连接的运行状况。如果联合连接健康,则远程代理会响应每个 keep-alive 消息。如果连接不健康,当下游代理无法接收来自上游代理的响应时,会使用名为 断路器 的机制来阻止联合消费者。如需更多信息,请参阅 circuit-breaker-timeout 参数的描述。check-period 参数的默认值为 30000
circuit-breaker-timeout
下游和上游代理之间的单个连接可能由许多联合队列和地址消费者共享。如果代理间的连接丢失,每个联合消费者可能会尝试同时重新连接。为避免这种情况,称为 断路器 的机制将阻止消费者。当指定的超时值 elapses 时,断路器重新尝试连接。如果成功,则使用者将被取消阻塞。否则,再次应用断路器。
connection-ttl
如果联合连接停止从远程代理接收信息,则以毫秒为单位的连接会保持活跃时间。默认值为 60000
discovery-group-ref
作为为到上游代理定义静态连接器的替代选择,此元素可用于指定已在 broker.xml 配置文件中其他位置配置的发现组。具体来说,您可以将一个现有的 discovery 组指定为此元素的 discovery-group-name 属性的值。有关发现组的更多信息,请参阅 第 14.1.6 节 “代理发现方法”
ha
指定是否为连接到上游代理启用高可用性。如果此参数的值被设置为 true,则本地代理可以连接到上游集群中的任何可用代理,并在实时上游代理关闭时自动故障切换到备份代理。默认值为 false
initial-connect-attempts
下游代理要连接到上游代理的初始尝试次数。如果在没有建立连接的情况下达到这个值,则上游代理被视为永久离线。下游代理不再将消息路由到上游代理。默认值为 -1,这表示没有限制。
max-retry-interval
当连接到远程代理失败时,后续重新连接尝试之间的最长时间(以毫秒为单位)。默认值为 2000
reconnect-attempts
如果连接失败,下游代理会尝试重新连接到上游代理的次数。如果在没有重新建立连接的情况下达到这个值,则上游代理被视为永久离线。下游代理不再将消息路由到上游代理。默认值为 -1,这表示没有限制。
retry-interval
如果连接到远程代理失败,则在后续的重新连接尝试之间以毫秒为单位为单位。默认值为 500
retry-interval-multiplier
应用于 retry-interval 参数的值的倍数。默认值为:1
share-connection

如果为同一代理同时配置了下游和上游连接,那么只要下游和上游配置都将把这个参数的值设置为 true,就可以共享同一连接。默认值为 false

  1. 在本地代理上,将连接器添加到远程代理中。这些是在联合地址配置 的静态连接器 元素中引用的连接器。例如:

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

4.22.9. 配置下游队列联合

以下示例演示了如何配置下游队列联合。

借助下游队列联合,可以在一个或多个远程代理用来连接到本地代理的本地代理中添加配置。这种方法的优势在于,您可以在单个代理中保留所有联合配置。这可能是 hub 和spoke 拓扑的一个实用方法,例如:

注意

下游队列联合会反转连接与上游队列配置的方向。因此,当您在配置中添加远程代理时,这些代理被视为 下游 代理。下游代理使用配置中的连接信息重新连接到本地代理,该代理现在被视为上游。当您为远程代理添加配置时,本例中会对此进行说明。

先决条件

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 添加包括 <federation> 项的 <federations> 项。例如:

    <federations>
      <federation name="eu-north-1" user="federation_username" password="32a10275cf4ab4e9">
      </federation>
    </federations>
  3. 添加队列策略配置。例如:

    <federations>
        ...
        <federation name="eu-north-1" user="federation_username" password="32a10275cf4ab4e9">
    
            <queue-policy name="news-queue-federation" priority-adjustment="-5" include-federated="true" transformer-ref="new-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>
    
        </federation>
      ...
    </federations>
  4. 如果要在传输前转换消息,请添加转换器配置。例如:

    <federations>
        ...
        <federation name="eu-north-1" user="federation_username" password="32a10275cf4ab4e9">
    
            <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>
  5. 为每个远程代理添加 downstream 项。例如:

    <federations>
        ...
        <federation name="eu-north-1" user="federation_username" password="32a10275cf4ab4e9">
    
            <downstream name="eu-east-1">
                <static-connectors>
                    <connector-ref>eu-east-connector1</connector-ref>
                </static-connectors>
                <transport-connector-ref>netty-connector</transport-connector-ref>
                <policy ref="news-address-federation"/>
            </downstream>
    
            <downstream name="eu-west-1" >
                <static-connectors>
                    <connector-ref>eu-west-connector1</connector-ref>
                </static-connectors>
                <transport-connector-ref>netty-connector</transport-connector-ref>
                <policy ref="news-address-federation"/>
            </downstream>
    
            <queue-policy name="news-queue-federation" priority-adjustment="-5" include-federated="true" transformer-ref="new-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>

    如前面的配置所示,远程代理现在被视为本地代理的下游。下游代理使用配置中的连接信息来回连接本地(即 上游)代理。

  6. 在本地代理上,添加供本地和远程代理使用的连接器和接收器来建立联合连接。例如:

    <connectors>
       <connector name="netty-connector">tcp://localhost:61616</connector>
       <connector name="eu-west-1-connector">tcp://localhost:61616</connector>
       <connector name="eu-east-1-connector">tcp://localhost:61617</connector>
    </connectors>
    
    <acceptors>
       <acceptor name="netty-acceptor">tcp://localhost:61616</acceptor>
    </acceptors>
    连接器名称="netty-connector"
    本地代理发送到远程代理的连接器配置。远程代理使用此配置连接回本地代理。
    连接器名称="eu-west-1-connector" , connector name="eu-east-1-connector"
    远程代理的连接器。本地代理使用这些连接器连接到远程代理,并共享远程代理所需的配置来回连接本地代理。
    acceptor name="netty-acceptor"
    与远程代理使用的连接器对应的本地代理中的接受者,以连接至本地代理。

第 5 章 保护代理

5.1. 保护连接

当代理连接到消息传递客户端时,或者代理连接到其他代理时,您可以使用传输层安全(TLS)保护这些连接。

您可以使用两个 TLS 配置:

  • 单向 TLS,其中只有代理提供证书。这是最常见的配置。
  • 双向(或 mutual)TLS,其中代理和客户端(或其他代理)都提供证书。

本节中的步骤演示了如何配置单向和双向 TLS。

5.1.1. 配置单向 TLS

以下流程演示了如何为单向 TLS 配置给定接受者。

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 对于给定的 acceptor,添加 sslEnabled 键并将值设为 true。另外,添加 keyStorePathkeyStorePassword 密钥。设置与代理键存储对应的值。例如:

    <acceptor name="artemis">tcp://0.0.0.0:61616?sslEnabled=true;keyStorePath=../etc/broker.keystore;keyStorePassword=1234!</acceptor>

5.1.2. 配置双向 TLS

以下步骤演示了如何配置双向 TLS。

先决条件

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 对于您之前为单向 TLS 配置的接收器,添加 needClientAuth 密钥。将值设为 true。例如:

    <acceptor name="artemis">tcp://0.0.0.0:61616?sslEnabled=true;keyStorePath=../etc/broker.keystore;keyStorePassword=1234!;needClientAuth=true</acceptor>
  3. 上一步的配置假定客户端证书由可信提供者签名。如果客户端的证书 不是由 可信提供者(例如,自签名的签名)签名,则代理需要将客户端证书导入信任存储中。在这种情况下,添加 trustStorePathtrustStorePassword 密钥。设置与代理信任存储对应的值。例如:

    <acceptor name="artemis">tcp://0.0.0.0:61616?sslEnabled=true;keyStorePath=../etc/broker.keystore;keyStorePassword=1234!;needClientAuth=true;trustStorePath=../etc/client.truststore;trustStorePassword=5678!</acceptor>
注意

AMQ Broker 支持多个协议,每个协议和平台都有不同的方法来指定 TLS 参数。但是,在使用 Core Protocol(一个桥接)的客户端时,TLS 参数在连接器 URL 上配置,这与代理的接受者非常相似。

5.1.3. TLS 配置选项

下表显示了所有可用的 TLS 配置选项。

选项备注

sslEnabled

指定是否为连接启用 SSL。必须设置为 true 才能启用 TLS。默认值为 false

keyStorePath

在接受者: 到持有代理证书的代理上的 TLS 密钥存储路径(无论是由认证机构进行自签名或签名)的代理上时。

连接器上用作时: 包含客户端证书的客户端上的 TLS 密钥存储路径。仅在使用双向 TLS 时,这与连接器相关。虽然您可以在代理上配置这个值,但它由客户端下载并使用。如果客户端需要使用与代理上设置的不同路径,可以使用标准的 javax.net.ssl.keyStore 系统属性或 AMQ 特定的 org.apache.ssl.keyStore 系统属性覆盖代理设置。如果客户端上的另一个组件已经使用标准 Java 系统属性,则 AMQ 特定系统属性很有用。

keyStorePassword

在代理上使用的 acceptor: Password 作为代理上的密钥存储。

在连接器中使用时,密码用于客户端上的密钥存储。仅在使用双向 TLS 时,这与连接器相关。虽然您可以在代理上配置这个值,但它由客户端下载并使用。如果客户端需要使用代理上设置的不同密码,可以使用标准的 javax.net.ssl.keyStorePassword 系统属性或 AMQ 特定的 org.apache.keyStorePassword 系统属性覆盖代理设置。如果客户端上的另一个组件已经使用标准 Java 系统属性,则 AMQ 特定系统属性很有用。

trustStorePath

在接受者: 到含有代理信任的所有客户端密钥的代理上的 TLS 信任存储的路径。仅在使用双向 TLS 时,这与接受者相关。

连接器中使用时: 在包含客户端信任的所有代理的公钥的客户端上的 TLS 信任存储的路径。虽然您可以在代理上配置这个值,但它由客户端下载并使用。如果客户端需要使用与服务器上设置的不同路径,那么它可以通过使用标准的 javax.net.ssl.trustStore 系统属性或 AMQ- specific org.apache.ROKSStore 系统属性覆盖服务器端设置。如果客户端上的另一个组件已经使用标准 Java 系统属性,则 AMQ 特定系统属性很有用。

trustStorePassword

当用于接受器: 代理中信任存储的密码。仅在使用双向 TLS 时,这与接受者相关。

在连接器中使用时: 客户端的信任存储的密码。虽然您可以在代理上配置这个值,但它由客户端下载并使用。如果客户端需要使用代理上设置的不同密码,可以使用标准的 javax.net.ssl.trustStorePassword 系统属性或 AMQ-specific org.ssl.trustStorePassword 系统属性覆盖代理设置。如果客户端上的另一个组件已经使用标准 Java 系统属性,则 AMQ 特定系统属性很有用。

enabledCipherSuites

无论是在接受者还是连接器中,这是用于 TLS 通信的以逗号分隔的密码套件列表。默认值为 null,即使用 JVM 的默认。

enabledProtocols

无论是在接受者还是连接器中,这是用于 TLS 通信的以逗号分隔的协议列表。默认值为 null,即使用 JVM 的默认。

needClientAuth

此属性仅适用于接受者。它指示客户端连接到需要双向 TLS 的接受器。有效值为 true 或者 false。默认值为 false

5.2. 验证客户端

5.2.1. 客户端验证方法

要在代理中配置客户端身份验证,您可以使用以下方法:

用户名和密码的身份验证

使用这些选项之一直接验证用户凭证:

  • 针对保存在代理中的一组属性文件检查凭证。您还可以配置允许有限访问代理 的客户机 帐户,并组合登录模块以支持更复杂的用例。
  • 配置 轻量级目录访问协议(LDAP)登录模块,以根据中央 X.500 目录服务器 中存储的用户数据检查客户端凭据。
基于证书的验证
配置双向 传输层安全 (TLS),要求代理和客户端提供证书以进行 mutual身份验证。管理员还必须配置属性文件,以定义批准的客户端用户和角色。这些属性文件存储在代理中。
基于 Kerberos 的身份验证
配置代理以使用简单验证 和安全层(SASL)框架中的 GSSAPI 机制验证 客户端的 Kerberos 安全凭证。

下面的部分论述了如何配置用户和基于证书的身份验证。

其他资源

5.2.2. 根据属性文件配置用户和密码身份验证

AMQ Broker 支持灵活的基于角色的安全模型,以根据地址将安全性应用到队列。队列绑定到地址一到一(用于点到点的消息传递)或多对方(用于发布订阅消息传递)。当消息发送到地址时,代理会查找绑定到该地址的队列集合,并将消息路由到该队列集。

当您需要基本用户和密码身份验证时,请使用 PropertiesLoginModule 定义它。这个登录模块会根据保存在代理中的以下配置文件检查用户凭证:

artemis-users.properties
用于定义用户和对应密码
artemis-roles.properties
用于定义角色并将用户分配给这些角色
login.config
用于配置登录模块用于用户和密码身份验证和客户端访问

artemis-users.properties 文件可包含哈希密码,以提高安全性。

以下部分介绍了如何配置:

5.2.2.1. 配置基本用户和密码身份验证

以下步骤演示了如何配置基本用户和密码身份验证。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/login.config 配置文件。默认情况下,新的 AMQ Broker 7.10 实例中的此文件包括以下行:

    activemq {
       org.apache.activemq.artemis.spi.core.security.jaas.PropertiesLoginModule sufficient
           debug=false
           reload=true
           org.apache.activemq.jaas.properties.user="artemis-users.properties"
           org.apache.activemq.jaas.properties.role="artemis-roles.properties";
             };
    activemq
    配置的别名。
    org.apache.activemq.artemis.spi.core.security.jaas.PropertiesLoginModule
    实施类。
    足够

    标志指定 PropertiesLoginModule 所需的成功级别。您可以设置的值有:

    • 必需 :需要登录模块才能成功。身份验证将继续关闭在给定别名中配置的登录模块列表,无论成功还是失败。
    • 先决条件 :需要登录模块才能成功。现在,失败会将控制权返回给应用程序。身份验证不会继续关闭在给定别名中配置的登录模块列表。
    • sufficient :登录模块不需要成功。如果成功,控制会返回到应用程序,且身份验证不会进一步。如果失败,身份验证会尝试继续关闭给定别名中配置的登录模块列表。
    • 可选 : 成功不需要登录模块。身份验证将继续在给定别名下配置的登录模块列表,无论成功还是失败。
    org.apache.activemq.jaas.properties.user
    指定用于为登录模块实施定义一组用户和密码的属性文件。
    org.apache.activemq.jaas.properties.role
    指定属性文件,用于将用户映射到为登录模块实施定义的角色。
  2. 打开 & lt;broker_instance_dir&gt; /etc/artemis-users.properties 配置文件。
  3. 添加用户并为用户分配密码。例如:

    user1=secret
    user2=access
    user3=myPassword
  4. 打开 & lt;broker_instance_dir&gt; /etc/artemis-roles.properties 配置文件。
  5. 将角色名称分配给您之前添加到 artemis-users.properties 文件中的用户。例如:

    admin=user1,user2
    developer=user3
  6. 打开 & lt;broker_instance_dir&gt; /etc/bootstrap.xml 配置文件。
  7. 若有必要,将安全域别名( 在这个实例中)添加到该文件,如下所示:

    <jaas-security domain="activemq"/>
5.2.2.2. 配置客户端访问权限

对于没有登录凭证或凭证无法身份验证的用户,您可以使用客户机帐户授予对代理的有限访问权限。

您可以使用 命令行参数创建启用虚拟客户机的代理实例;-- allow-anonymous (这是 --require-login)。

以下流程演示了如何配置客户端访问。

先决条件

流程

  1. 打开之前为基本用户和密码身份验证配置的 & lt;broker_instance_dir> /etc/login.config 配置文件。
  2. 在之前添加的属性登录模块配置后,添加客户机登录模块配置。例如:

    activemq {
      org.apache.activemq.artemis.spi.core.security.jaas.PropertiesLoginModule sufficient
          debug=true
          org.apache.activemq.jaas.properties.user="artemis-users.properties"
          org.apache.activemq.jaas.properties.role="artemis-roles.properties";
    
      org.apache.activemq.artemis.spi.core.security.jaas.GuestLoginModule sufficient
          debug=true
          org.apache.activemq.jaas.guest.user="guest"
          org.apache.activemq.jaas.guest.role="restricted";
    };
    org.apache.activemq.artemis.spi.core.security.jaas.GuestLoginModule
    实施类。
    org.apache.activemq.jaas.guest.user
    分配给匿名用户的用户名。
    org.apache.activemq.jaas.guest.role
    分配给匿名用户的角色。

根据上述配置,如果用户提供凭证,则会激活用户名和密码身份验证模块。如果用户不提供凭证,或者提供的凭证不正确,则会激活客户机身份验证。

5.2.2.2.1. 客户端访问示例

以下示例显示,在仅那些没有凭证的用户被设置为 guest 时,对客户机进行访问的配置。在本示例中,观察登录模块的顺序与之前的配置过程对比。另外,附加到属性登录模块的 标志被改为 requisite

activemq {
    org.apache.activemq.artemis.spi.core.security.jaas.GuestLoginModule sufficient
        debug=true
       credentialsInvalidate=true
       org.apache.activemq.jaas.guest.user="guest"
       org.apache.activemq.jaas.guest.role="guests";

    org.apache.activemq.artemis.spi.core.security.jaas.PropertiesLoginModule requisite
        debug=true
        org.apache.activemq.jaas.properties.user="artemis-users.properties"
        org.apache.activemq.jaas.properties.role="artemis-roles.properties";
};

根据上述配置,如果没有提供登录凭证,则会激活客户机身份验证模块。

在这种情况下,在 guest 登录模块配置中,credentialsInvalidate 选项必须设为 true

如果提供了凭证,则激活属性登录模块。凭证必须是有效的。

其他资源

5.2.3. 配置基于证书的验证

Java 认证和授权 服务(JAAS)证书登录模块处理使用传输层安全(TLS)的客户端的身份验证和授权。该模块需要使用双向 传输层安全 (TLS),才能利用客户端配置自己的证书。身份验证在 TLS 握手期间执行,而不是直接由 JAAS 证书登录模块执行。

证书登录模块的角色是:

  • 限制可接受的用户集合。只有相关属性文件中明确列出的用户可辨识 名称 (DN)才有资格进行身份验证。
  • 将组列表与收到的用户身份关联。这有助于授权。
  • 要求存在传入的客户端证书(默认情况下,TLS 层被配置为将客户端证书视为可选)。

证书登录模块将证书 DN 的集合存储在一对平面文本文件中。文件将用户名及组 ID 列表与每个 DN 关联。

证书登录模块由 org.apache.activemq.artemis.spi.core.security.jaas.TextFileCertificateLoginModule 类实施。

5.2.3.1. 配置代理以使用基于证书的身份验证

以下流程演示了如何将代理配置为使用基于证书的身份验证。

先决条件

流程

  1. 从之前导入到代理密钥存储的用户证书获取 Subject Distinguished Names (DNs)。

    1. 将密钥文件中的证书导出到一个临时文件中。例如:

      keytool -export -file <file_name> -alias broker-localhost -keystore broker.ks -storepass <password>
    2. 输出导出证书的内容:

      keytool -printcert -file <file_name>

      输出结果类似如下:

      Owner: CN=localhost, OU=broker, O=Unknown, L=Unknown, ST=Unknown, C=Unknown
      Issuer: CN=localhost, OU=broker, O=Unknown, L=Unknown, ST=Unknown, C=Unknown
      Serial number: 4537c82e
      Valid from: Thu Oct 19 19:47:10 BST 2006 until: Wed Jan 17 18:47:10 GMT 2007
      Certificate fingerprints:
               MD5:  3F:6C:0C:89:A8:80:29:CC:F5:2D:DA:5C:D7:3F:AB:37
               SHA1: F0:79:0D:04:38:5A:46:CE:86:E1:8A:20:1F:7B:AB:3A:46:E4:34:5C

      Owner 条目是 Subject DN。用于输入 Subject DN 的格式取决于您的平台。以上字符串也可以表示为;

      Owner: `CN=localhost,\ OU=broker,\ O=Unknown,\ L=Unknown,\ ST=Unknown,\ C=Unknown`
  2. 配置基于证书的验证。

    1. 打开 & lt;broker_instance_dir&gt; /etc/login.config 配置文件。添加证书登录模块并引用用户和角色属性文件。例如:

      activemq {
          org.apache.activemq.artemis.spi.core.security.jaas.TextFileCertificateLoginModule
              debug=true
              org.apache.activemq.jaas.textfiledn.user="artemis-users.properties"
              org.apache.activemq.jaas.textfiledn.role="artemis-roles.properties";
      };
      org.apache.activemq.artemis.spi.core.security.jaas.TextFileCertificateLoginModule
      实施类。
      org.apache.activemq.jaas.textfiledn.user
      指定用于为登录模块实施定义一组用户和密码的属性文件。
      org.apache.activemq.jaas.textfiledn.role
      指定属性文件,用于将用户映射到为登录模块实施定义的角色。
    2. 打开 & lt;broker_instance_dir&gt; /etc/artemis-users.properties 配置文件。在此 文件中定义了用户及其对应的 DN。例如:

      system=CN=system,O=Progress,C=US
      user=CN=humble user,O=Progress,C=US
      guest=CN=anon,O=Progress,C=DE

      例如,根据上述配置,名为 system 的用户映射到 CN=system,O=Progress,C=US Subject DN。

    3. 打开 & lt;broker_instance_dir&gt; /etc/artemis-roles.properties 配置文件。可用的角色和拥有这些角色的用户在此文件中定义。例如:

      admins=system
      users=system,user
      guests=guest

      在前面的配置中,对于 users 角色,您将以逗号分隔列表列出多个用户。

    4. 请确保您的安全域别名(在本例中是 activemq)在 bootstrap.xml 中引用,如下所示:

      <jaas-security domain="activemq"/>
5.2.3.2. 为 AMQP 客户端配置基于证书的验证

使用 Simple Authentication and Security Layer (SASL)EXTERNAL 机制配置参数,在连接到代理时将您的 AQMP 客户端配置为基于证书的验证。

代理会以验证任何证书的相同方式验证您的 AMQP 客户端的 Transport Layer Security (TLS)/Secure Sockets Layer (SSL) 证书:

  1. 代理读取客户端的 TLS/SSL 证书,以便从证书的主题获取身份。
  2. 证书主题映射到证书登录模块的代理身份。然后,代理会基于其角色授权用户。

以下流程演示了如何为 AMQP 客户端配置基于证书的身份验证。要启用 AMQP 客户端使用基于证书的身份验证,您必须将配置参数添加到客户端用于连接代理的 URI 中。

先决条件

流程

  1. 打开包含要编辑 URI 的资源:

    amqps://localhost:5500
  2. 添加参数 sslEnabled=true 来为连接启用 TSL/SSL:

    amqps://localhost:5500?sslEnabled=true
  3. 添加与客户端信任存储和密钥存储相关的参数,以便使用代理启用 TSL/SSL 证书交换:

    amqps://localhost:5500?sslEnabled=true&trustStorePath=<trust_store_path>&trustStorePassword=<trust_store_password>&keyStorePath=<key_store_path>&keyStorePassword=<key_store_password>
  4. 添加参数 saslMechanisms=EXTERNAL,使用 TSL/SSL 证书中找到的身份请求代理来验证客户端:

    amqps://localhost:5500?sslEnabled=true&trustStorePath=<trust_store_path>&trustStorePassword=<trust_store_password>&keyStorePath=<key_store_path>&keyStorePassword=<key_store_password>&saslMechanisms=EXTERNAL

其他资源

5.3. 授权客户端

5.3.1. 客户端授权方法

要授权客户端在代理上执行操作,如创建和删除地址和队列,以及发送和接收消息,您可以使用以下方法:

基于用户和基于角色的授权
为经过身份验证的用户和角色配置代理安全设置。
配置 LDAP 以授权客户端
配置 轻量级目录访问协议( LDAP)登录模块,以同时处理身份验证和授权。LDAP 登录模块根据存储在中央 X.500 目录服务器中的用户数据检查传入的凭证,并根据用户角色设置权限。
配置 Kerberos 以授权客户端
配置 Java 身份验证和授权服务 (JAAS) Krb5LoginModule 登录模块,将凭证传递给 PropertiesLoginModuleLDAPLoginModule 登录模块,它会将 Kerberos 验证的用户映射到 AMQ Broker 角色。

5.3.2. 配置基于用户和基于角色的授权

5.3.2.1. 设置权限

通过 broker.xml 配置文件中的 < security-setting&gt; 元素根据队列(基于其地址)定义权限。您可以在配置文件的 <security-settings> 项中定义多个 <security-setting> 实例。您可以指定准确的地址匹配,也可以使用数字符号(#)和星号(*)通配符定义通配符匹配。

可以向与地址匹配的队列授予不同的权限。这些权限在下表中显示。

允许用户进入…​使用此参数…​

创建地址

createAddress

删除地址

deleteAddress

在匹配的地址下创建一个持久队列

createDurableQueue

删除匹配地址下的持久队列

deleteDurableQueue

在匹配的地址下创建不可durable 队列

createNonDurableQueue

删除匹配地址下的不可durable 队列

deleteNonDurableQueue

向匹配的地址发送消息

send

使用来自绑定到匹配地址的队列的消息

consume

通过将管理消息发送到管理地址调用管理操作

管理

浏览绑定到匹配地址的队列

browse

对于每个权限,您可以指定授予该权限的角色列表。如果给定用户具有任何角色,则会授予他们该组地址的权限。

下面的部分显示了一些权限配置示例。

5.3.2.1.1. 为单个地址配置消息生产环境

以下流程演示了如何为单一地址配置消息生产权限。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. <security-settings> 项中添加一个单一的 <security-setting> 项。对于 match 键,指定一个地址。例如:

    <security-settings>
        <security-setting match="my.destination">
            <permission type="send" roles="producer"/>
        </security-setting>
    </security-settings>

    根据上述配置,制作者 角色的成员具有地址 my.destination发送 权限。

5.3.2.1.2. 为单个地址配置消息消耗

以下流程演示了如何为单一地址配置消息消耗权限。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. <security-settings> 项中添加一个单一的 <security-setting> 项。对于 match 键,指定一个地址。例如:

    <security-settings>
        <security-setting match="my.destination">
            <permission type="consume" roles="consumer"/>
        </security-setting>
    </security-settings>

    根据上述配置,consumer 角色的成员具有地址 my.destinationconsume 权限。

5.3.2.1.3. 在所有地址上配置完全访问权限

以下流程演示了如何配置对所有地址和相关队列的完整访问权限。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. <security-settings> 项中添加一个单一的 <security-setting> 项。对于 match 键,要配置 对所有 地址的访问,请指定数字符号(#)通配符。例如:

    <security-settings>
        <security-setting match="#">
            <permission type="createDurableQueue" roles="guest"/>
            <permission type="deleteDurableQueue" roles="guest"/>
            <permission type="createNonDurableQueue" roles="guest"/>
            <permission type="deleteNonDurableQueue" roles="guest"/>
            <permission type="createAddress" roles="guest"/>
            <permission type="deleteAddress" roles="guest"/>
            <permission type="send" roles="guest"/>
            <permission type="browse" roles="guest"/>
            <permission type="consume" roles="guest"/>
            <permission type="manage" roles="guest"/>
        </security-setting>
    </security-settings>

    根据上述配置,所有权限都将赋予所有 队列的客户机 角色的成员。这在配置了匿名身份验证以为每个用户分配 客户机 角色的开发场景中很有用。

其他资源

5.3.2.1.4. 配置多个安全设置

以下示例步骤演示了如何为匹配的地址集单独配置多个安全设置。这与本节中前面的示例相反,它演示了如何为 所有地址授予完全访问权限

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. <security-settings> 项中添加一个单一的 <security-setting> 项。对于 match 键,包括数字符号(#)通配符字符,以将设置应用到匹配的地址 。例如:

    <security-setting match="globalqueues.europe.#">
       <permission type="createDurableQueue" roles="admin"/>
       <permission type="deleteDurableQueue" roles="admin"/>
       <permission type="createNonDurableQueue" roles="admin, guest, europe-users"/>
       <permission type="deleteNonDurableQueue" roles="admin, guest, europe-users"/>
       <permission type="send" roles="admin, europe-users"/>
       <permission type="consume" roles="admin, europe-users"/>
    </security-setting>
    match=globalqueues.europe.#
    数字符号(#)通配符字符由代理解释为"任意单词序列"。词语以句点()分隔在本例中,安全设置应用于以字符串 globalqueues.europe开头的任何地址。
    权限类型="createDurableQueue"
    只有具有 admin 角色的用户才能创建或删除 durable 队列,绑定到以字符串 globalqueues.europe开头的地址。
    权限类型="createNonDurableQueue"
    任何具有 adminguesteurope-users 角色的用户都可以创建或删除绑定到字符串 globalqueues.europe开头的临时队列。
    权限类型="send"
    具有 admineurope-users 角色的任何用户可以发送消息到绑定到以字符串 globalqueues.europe开头的地址的队列。
    权限类型="consume"
    任何具有 admineurope-users 角色的用户都可以使用绑定到以字符串 globalqueues.europe开头的地址的队列中的消息。
  3. (可选)将不同的安全设置应用到更严格的地址集合,请添加另一个 < security-setting> 元素。对于 match 键,请指定更具体的文本字符串。例如:

    <security-setting match="globalqueues.europe.orders.#">
       <permission type="send" roles="europe-users"/>
       <permission type="consume" roles="europe-users"/>
    </security-setting>

    在第二个 security-setting 元素中,globalqueues.europe.orders.# match 比第一个 security-setting 元素中指定的 globalqueues.europe.# 匹配更具体。对于匹配 globalqueues.europe.orders.# 的每个地址,存在权限 createDurableQueue,deleteDurableQueue,createNonDurableQueue,deleteNonDurableQueue 不会从 文件中的第一个 security-setting 元素继承。例如,对于地址 globalqueues.europe.orders.plastics,存在的唯一权限会被 发送 并消耗 角色 europe-users

    因此,由于在一个 security-setting 块中指定的权限不会被另一个继承,所以您可以通过指定这些权限来有效地拒绝更具体的 security-setting 块的权限。

5.3.2.1.5. 使用用户配置队列

当一个队列被自动创建时,队列会被分配连接客户端的用户名。此用户名作为队列的元数据包含在内。该名称由 JMX 和 AMQ Broker 管理控制台公开。

以下流程演示了如何将用户名添加到您在代理配置中手动定义的队列。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 对于给定的队列,添加用户 密钥。分配值。例如:

    <address name="ExampleQueue">
        <anycast>
           <queue name="ExampleQueue" user="admin"/>
        </anycast>
    </address>

    根据上述配置,admin 用户分配给队列 ExampleQueue

注意
  • 在队列中配置用户不会更改该队列的任何安全语义 - 它仅用于该队列中的元数据。
  • 用户与角色之间的映射,由名为 安全管理器 的组件处理。安全管理器从存储在代理上的属性文件中读取用户凭据。默认情况下,AMQ Broker 使用 org.apache.activemq.artemis.spi.security.security.ActiveMQJAASSecurityManager 安全管理器。此默认安全管理器与红帽 JBoss 企业应用平台(JBoss EAP)安全性提供集成。

    要了解如何 使用自定义 安全管理器,请参阅 第 5.6.2 节 “指定自定义安全管理器”

5.3.2.2. 配置基于角色的访问控制

基于角色的访问控制 (RBAC)用于限制对 MBeans 属性和方法的访问。RBAC 可让管理员根据角色向所有用户(如 Web 控制台、管理界面和核心信息等)授予正确的访问权限级别。

5.3.2.2.1. 配置基于角色的访问控制

以下示例流程演示了如何将角色映射到特定的 MBeans 及其属性和方法。

先决条件

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/management.xml 配置文件。
  2. 搜索 role-access 元素并编辑配置。例如:

    <role-access>
        <match domain="org.apache.activemq.artemis">
           <access method="list*" roles="view,update,amq"/>
           <access method="get*" roles="view,update,amq"/>
           <access method="is*" roles="view,update,amq"/>
           <access method="set*" roles="update,amq"/>
           <access method="*" roles="amq"/>
        </match>
    </role-access>
    • 在本例中,匹配应用到任何 MBean 属性,其域名为 org.apache. located.apache.apache.apache
    • 访问 view, update, 或 amq 角色来匹配 MBean 属性由您添加到角色的 list*, get*, set*, is*, 和 * 访问方法控制。方法="*" (wildcard)语法用作一种捕获方式,用于指定配置中没有列出的所有其他方法。配置中的每个访问方法都会转换为 MBean 方法调用。
    • 调用的 MBean 方法与配置中列出的方法匹配。例如,如果您在带有 org.apache.activemq.artemis 域的 MBean 上调用 listMessages 的方法,则代理将访问返回到 列表 方法配置中定义的角色。
    • 您还可以使用完整的 MBean 方法名称配置访问权限。例如:

      <access method="listMessages" roles="view,update,amq"/>
  3. 启动或重启代理。

    • 在 Linux: & lt;broker_instance_dir&gt; /bin/artemis run
    • 在 Windows: & lt;broker_instance_dir&gt; \bin\artemis-service.exe start

您也可以通过添加与 MBean 属性匹配的 key 属性,在域中匹配特定的 MBeans。

5.3.2.2.2. 基于角色的访问控制示例

本节显示了以下应用基于角色的访问控制的示例:

以下示例演示了如何使用 key 属性将角色映射到指定域中的所有队列。

<match domain="org.apache.activemq.artemis" key="subcomponent=queues">
   <access method="list*" roles="view,update,amq"/>
   <access method="get*" roles="view,update,amq"/>
   <access method="is*" roles="view,update,amq"/>
   <access method="set*" roles="update,amq"/>
   <access method="*" roles="amq"/>
</match>

以下示例演示了如何使用 key 属性将角色映射到特定的命名队列。在本例中,named queue 是 exampleQueue

<match domain="org.apache.activemq.artemis" key="queue=exampleQueue">
   <access method="list*" roles="view,update,amq"/>
   <access method="get*" roles="view,update,amq"/>
   <access method="is*" roles="view,update,amq"/>
   <access method="set*" roles="update,amq"/>
   <access method="*" roles="amq"/>
</match>

以下示例演示了如何将角色映射到名称包含指定前缀的每个队列。在本例中,使用星号(*)通配符运算符匹配所有以前缀 example 开头的队列名称。

<match domain="org.apache.activemq.artemis" key="queue=example*">
   <access method="list*" roles="view,update,amq"/>
   <access method="get*" roles="view,update,amq"/>
   <access method="is*" roles="view,update,amq"/>
   <access method="set*" roles="update,amq"/>
   <access method="*" roles="amq"/>
</match>

您可能希望针对同一属性的不同组(例如,不同的队列集合)映射不同的角色。在这种情况下,您可以在配置文件中包含多个 匹配 元素。但是,在同一域中可以有多个匹配项。

例如,考虑配置了两个 &lt ;match& gt; 元素,如下所示:

<match domain="org.apache.activemq.artemis" key="queue=example*">

<match domain="org.apache.activemq.artemis" key="queue=example.sub*">

根据此配置,org.apache.activemq.artemis 域中的名为 example.sub.queue 的队列与两个通配符键表达式匹配。因此,代理需要一个优先方案来决定哪组角色映射到队列;在第一个 match 项中指定的角色,或在第二个 match 项中指定的角色。

当同一域中有多个匹配项时,代理会在映射角色时使用以下优先级:

  • 完全匹配优先于通配符匹配
  • 通配符匹配时间超过较短的通配符匹配项

在本例中,因为较长的通配符表达式与 example.sub.queue 的队列名称匹配,因此代理会应用在第二个 < match > 元素中配置的 role-mapping。

注意

default-access 元素是每个方法调用的 catch-all 元素,不使用 role-accesswhitelist 配置来处理。default-accessrole-access 元素具有相同的 match 元素语义。

5.3.2.2.3. 配置 whitelist 元素

白名单是一组预先批准的域或 MBeans,不需要用户身份验证。您可以提供必须绕过身份验证的域列表或 MBeans 列表。例如,您可以使用白名单来指定 AMQ Broker 管理控制台需要的任何 MBeans。

以下示例流程演示了如何配置 白名单 元素。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/management.xml 配置文件。
  2. 搜索 whitelist 元素并编辑配置:

    <whitelist>
       <entry domain="hawtio"/>
    </whitelist>

    在这个示例中,任何带有域 hawtio 的 MBean 被允许在没有身份验证的情况下进行访问。您还可以为 MBean 属性使用表单 < entry domain="hawtio" key="type=*"/& gt; 的通配符条目来匹配。

  3. 启动或重启代理。

    • 在 Linux: & lt;broker_instance_dir&gt; /bin/artemis run
    • 在 Windows: & lt;broker_instance_dir&gt; \bin\artemis-service.exe start
5.3.2.3. 设置资源限值

有时,在与授权和身份验证相关的普通安全设置之外,设置特定的限制会很有帮助。

5.3.2.3.1. 配置连接和队列限制

以下示例步骤演示了如何限制用户可以创建的连接和队列的数量。

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 添加 resource-limit-settings 元素。为 max-connectionsmax-queues 指定值。例如:

    <resource-limit-settings>
       <resource-limit-setting match="myUser">
          <max-connections>5</max-connections>
          <max-queues>3</max-queues>
       </resource-limit-setting>
    </resource-limit-settings>
    max-connections
    定义匹配用户可以向代理发出的连接数量。默认值为 -1,这表示没有限制。
    max-queues
    定义匹配用户可以创建的队列数。默认值为 -1,这表示没有限制。
注意

与您在 代理配置address-setting 元素中指定的匹配字符串不同,您在 resource-limit-settings 中指定的 match 字符串 无法 使用通配符语法。相反,match 字符串会定义一个特定用户,用于应用资源限值设置。

5.4. 使用 LDAP 进行身份验证和授权

LDAP 登录模块通过针对存储在中央 X.500 目录服务器中的用户数据检查传入的凭证来启用身份验证和授权。它由 org.apache.activemq.artemis.spi.core.security.jaas.LDAPLoginModule 来实施。

5.4.1. 配置 LDAP 以验证客户端

以下示例流程演示了如何使用 LDAP 验证客户端。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. security-settings 元素中,添加一个 security-setting 元素来配置权限。例如:

    <security-settings>
        <security-setting match="#">
            <permission type="createDurableQueue" roles="user"/>
            <permission type="deleteDurableQueue" roles="user"/>
            <permission type="createNonDurableQueue" roles="user"/>
            <permission type="deleteNonDurableQueue" roles="user"/>
            <permission type="send" roles="user"/>
            <permission type="consume" roles="user"/>
        </security-setting>
    </security-settings>

    上述配置将 所有 队列的特定权限分配给用户 角色的成员

  3. 打开 & lt;broker_instance_dir&gt; /etc/login.config 文件。
  4. 根据您要使用的目录服务配置 LDAP 登录模块。

    1. 如果您使用 Microsoft Active Directory 目录服务,请添加类似此示例的配置:

      activemq {
        org.apache.activemq.artemis.spi.core.security.jaas.LDAPLoginModule required
           debug=true
           initialContextFactory=com.sun.jndi.ldap.LdapCtxFactory
           connectionURL="LDAP://localhost:389"
           connectionUsername="CN=Administrator,CN=Users,OU=System,DC=example,DC=com"
           connectionPassword=redhat.123
           connectionProtocol=s
           connectionTimeout="5000"
           authentication=simple
           userBase="dc=example,dc=com"
           userSearchMatching="(CN={0})"
           userSearchSubtree=true
           readTimeout="5000"
           roleBase="dc=example,dc=com"
           roleName=cn
           roleSearchMatching="(member={0})"
           roleSearchSubtree=true
           ;
      };
      注意

      如果您使用 Microsoft Active Directory,且您需要为 connectionUsername 属性指定一个空格(例如,OU=System Accounts),那么您必须将该值包括在一个双引号(""),并使用反斜杠(\)来转义对中的每个双引用。例如,connectionUsername="CN=Administrator,CN=Users,OU=\"System Accounts\",DC=example,DC=com"。

    2. 如果您使用 ApacheDS 目录服务,请添加类似此示例的配置:

      activemq {
        org.apache.activemq.artemis.spi.core.security.jaas.LDAPLoginModule required
           debug=true
           initialContextFactory=com.sun.jndi.ldap.LdapCtxFactory
           connectionURL="ldap://localhost:10389"
           connectionUsername="uid=admin,ou=system"
           connectionPassword=secret
           connectionProtocol=s
           connectionTimeout=5000
           authentication=simple
           userBase="dc=example,dc=com"
           userSearchMatching="(uid={0})"
           userSearchSubtree=true
           userRoleName=
           readTimeout=5000
           roleBase="dc=example,dc=com"
           roleName=cn
           roleSearchMatching="(member={0})"
           roleSearchSubtree=true
           ;
      };
      debug
      打开"调试"(true)或关闭 (false)。默认值为 false
      initialContextFactory
      必须始终设置为 com.sun.jndi.ldap.LdapCtxFactory
      connectionURL
      使用 LDAP URL __<ldap://Host:Port>的目录服务器位置。可以选择通过添加正斜杠 / 以及在目录树中的特定节点的 DN 限定限定 URL。Apache DS 的默认端口为 10389,而 Microsoft AD 则是 389
      connectionUsername
      分辨名称(DN),用于打开与目录服务器的连接。例如: uid=admin,ou=system。目录服务器通常需要客户端提供用户名/密码凭证才能打开连接。
      connectionPassword
      与来自 connectionUsername 的 DN 匹配的密码。在目录服务器中,在 Directory Information Tree (DIT)中,密码通常以 userPassword 属性存储在对应的目录条目中。
      connectionProtocol
      任何值都受支持,但实际上没有使用。必须明确设置这个选项,因为它没有默认值。
      connectionTimeout

      指定代理可以连接到目录服务器的最大时间(以毫秒为单位)。如果代理在此时间内无法连接到 目录,它将中止连接尝试。如果为此属性指定 0 或更小的值,则会使用底层 TCP 协议的超时值。如果没有指定值,代理会等待无限期地建立连接,或者底层网络超时。

      当为连接请求了连接池时,这个属性指定代理在达到最大池大小并且池中所有连接都被使用时等待连接的最长时间。如果您指定了零个或更少值,则代理会无限期等待连接可用。否则,代理会在达到最大等待时间时中止连接尝试。

      身份验证
      指定绑定到 LDAP 服务器时使用的身份验证方法。此参数可设为 simple (需要用户名和密码)或 none (允许匿名访问)。
      userBase
      选择 DIT 的特定子树来搜索用户条目。子树由 DN 指定,用于指定子树的基本节点。例如,通过将这个选项设置为 ou=User,ou=ActiveMQ,ou=system,搜索用户条目仅限于 ou=User,ou=ActiveMQ,ou=system 节点下的子树。
      userSearchMatching
      指定 LDAP 搜索过滤器,它 应用到用户Base 选择的子树。详情请查看下面的 第 5.4.1.1 节 “搜索匹配的参数” 部分。
      userSearchSubtree
      相对于 用户Base 指定的节点,指定用户条目的搜索深度。这个选项是一个布尔值。指定一个 false 表示搜索尝试 与用户Base 节点的子条目之一匹配(映射到 javax.naming.directory.SearchControls.ONELEVEL_SCOPE)。指定一个 true 表示搜索会尝试与 属于用户Base 节点 的子树 的任何条目匹配(映射到 javax.naming.directory.SearchControls.SUBTREE_SCOPE)。
      userRoleName
      用户条目的属性名称,其中包含用户的角色名称列表。角色名称由代理的授权插件解释为组名称。如果省略这个选项,则不会从用户条目中提取角色名称。
      readTimeout
      指定代理可以等待从目录服务器收到响应到 LDAP 请求的最长时间(以毫秒为单位)。如果代理没有从目录服务器收到响应,代理会中止请求。如果您指定了零个或更少值,或者您没有指定值,代理会无限期等待目录服务器到 LDAP 请求的响应。
      roleBase
      如果角色数据直接存储在目录服务器中,可以使用角色选项的组合(角色BaseroleSearchMatchingroleSearchSubtreeroleName)作为指定 userRoleName 选项的替代选择。这个选项选择 DIT 的特定子树来搜索角色/组条目。子树由 DN 指定,用于指定子树的基本节点。例如,通过将这个选项设置为 ou=Group,ou=ActiveMQ,ou=system,搜索 role/group 条目仅限于 ou=Group,ou=ActiveMQ,ou=system 节点下的子树。
      roleName
      角色条目的属性类型,其中包含角色/组的名称(如 C、O、OU 等)。如果省略这个选项,则角色搜索功能会被实际禁用。
      roleSearchMatching
      指定 LDAP 搜索过滤器,它应用到由 角色Base 选择的子树。详情请查看下面的 第 5.4.1.1 节 “搜索匹配的参数” 部分。
      roleSearchSubtree

      指定与 角色Base 指定的节点相关的角色条目的搜索深度。如果设置为 false (默认值),则搜索尝试与 角色Base 节点的子条目之一匹配(映射到 javax.naming.directory.SearchControls.ONELEVEL_SCOPE)。如果为 true,它将尝试匹配角色Base 节点的子树的任何条目(映射到 javax.naming.directory.SearchControls.SUBTREE_SCOPE)。

      注意

      Apache DS 使用 DN 路径的 OID 部分。Microsoft Active Directory 使用 CN 部分。例如,您可以在 Apache DS 中使用 DN 路径,如 oid=testuser,dc=example,dc=com,而您可以在 Microsoft Active Directory 中使用 DN 路径,如 cn=testuser,dc=example,dc=com

  5. 启动或重启代理(service 或 process)。
5.4.1.1. 搜索匹配的参数
userSearchMatching

在传递到 LDAP 搜索操作前,此配置参数中提供的字符串值会受到字符串替换,如 java.text.MessageFormat 类所实施。

这意味着,特殊的字符串 {0} 替换为用户名,因为从传入的客户端凭证中提取。替换后,字符串将解释为 LDAP 搜索过滤器(语法由 IETF 标准 RFC 2254)定义)。

例如,如果此选项设置为 (uid={0}),并且收到的用户名为 jdoe,则搜索过滤器会在字符串替换后变为 (uid=jdoe)

如果生成的搜索过滤器应用到用户 base、ou=User,ou=ActiveMQ,ou=system 中选择的子树,它将匹配条目 uid=jdoe,ou=User,ou=ActiveMQ,ou=system

roleSearchMatching

这与 用户SearchMatching 选项类似,除了它支持两个替换字符串外。

替换字符串 {0} 替换匹配用户条目的完整 DN(即用户搜索的结果)。例如,对于用户 jdoe,替换的字符串可以是 uid=jdoe,ou=User,ou=ActiveMQ,ou=system

替换字符串 {1} 替换所接收的用户名。例如,jdo e

如果将此选项设置为 (member=uid={1}),并且收到的用户名为 jdoe,则搜索过滤器将在字符串替换后变为 (member=uid=jdoe) (假设 ApacheDS 搜索过滤器语法)。

如果生成的搜索过滤器应用于角色基础 ou=Group,ou=ActiveMQ,ou=system 中选择的子树,它将匹配 所有成员 属性等于 uid=jdoemember 属性的值是 DN)。

必须始终设置这个选项,即使角色搜索被禁用,因为它没有默认值。如果使用 OpenLDAP,搜索过滤器的语法为 (member:=uid=jdoe)

其他资源

5.4.2. 配置 LDAP 授权

LegacyLDAPSecuritySettingPlugin 安全设置插件读取之前在 AMQ 6 中由 LDAPAuthorizationMapcachedLDAPAuthorizationMap 控制的安全信息,并在可能的情况下将这个信息转换为对应的 AMQ 7 安全设置。

AMQ 6 和 AMQ 7 中代理的安全实现不完全匹配。因此,插件在两个版本之间执行一些转换,以获得近等功能。

以下示例演示了如何配置插件。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. security-settings 元素内,添加 security-setting-plugin 元素。例如:

    <security-settings>
        <security-setting-plugin class-name="org.apache.activemq.artemis.core.server.impl.LegacyLDAPSecuritySettingPlugin">
            <setting name="initialContextFactory" value="com.sun.jndi.ldap.LdapCtxFactory"/>
            <setting name="connectionURL" value="ldap://localhost:1024"/>`ou=destinations,o=ActiveMQ,ou=system`
            <setting name="connectionUsername" value="uid=admin,ou=system"/>
            <setting name="connectionPassword" value="secret"/>
            <setting name="connectionProtocol" value="s"/>
            <setting name="authentication" value="simple"/>
        </security-setting-plugin>
    </security-settings>
    class-name
    该实施是 org.apache.activemq.artemis.core.server.impl.LegacyLDAPSecuritySettingPlugin
    initialContextFactory
    用于连接到 LDAP 的初始上下文工厂。它必须始终设置为 com.sun.jndi.ldap.LdapCtxFactory (即默认值)。
    connectionURL
    使用 LDAP URL < ldap://Host:Port > 指定目录服务器的位置。您可以选择通过在目录树中添加正斜杠 /,后跟特定节点的可分辨名称(DN)来获取这个 URL。例如 :ldap://ldapserver:10389/ou=system默认值为 ldap://localhost:1024
    connectionUsername
    打开到目录服务器的连接的用户 DN。例如: uid=admin,ou=system。目录服务器通常需要客户端提供用户名/密码凭证才能打开连接。
    connectionPassword
    与来自 connectionUsername 的 DN 匹配的密码。在目录服务器中,在 Directory Information Tree (DIT)中,密码通常以 userPassword 属性存储在对应的目录条目中。
    connectionProtocol
    当前未使用的.以后,这个选项可能会允许您选择连接到目录服务器的安全套接字层(SSL)。必须明确设置这个选项,因为它没有默认值。
    身份验证

    指定绑定到 LDAP 服务器时使用的身份验证方法。此参数的有效值为 simple (用户名和密码)或 none (匿名)。默认值为 simple

    注意

    不支持 简单的身份验证和安全层(SASL)身份验证。

前面的配置示例中未显示的其他设置有:

destinationBase
指定子对象为所有目的地提供权限的节点的 DN。在本例中,DN 是字面值(即,不会对属性值执行字符串替换)。例如,这个属性的典型值是 ou=destinations,o=ActiveMQ,ou=system The defaults is ou=destinations,o=ActiveMQ,ou=system
filter
指定 LDAP 搜索过滤器,用于在查找任何类型的目标的权限时使用。搜索过滤器会尝试匹配其中一个队列或主题节点的子项或子代。默认值为 (cn=*)
roleAttribute
指定与 过滤器 匹配的节点属性,其值是角色的 DN。默认值为 uniqueMember
adminPermissionValue
指定与 admin 权限匹配的值。默认值为 admin
readPermissionValue
指定匹配 read 权限的值。默认值为 读取
writePermissionValue
指定匹配 write 权限的值。默认值为 write
enableListener
指定是否启用监听程序,它可自动接收 LDAP 服务器中的更新并实时更新代理的授权配置。默认值为 true
mapAdminToManage

指定是否将 legacy(即 AMQ 6) 管理员权限 映射到 AMQ 7 管理权限。请参考下表中映射语义的详情。默认值为 false

LDAP 中定义的队列或主题的名称充当安全设置的"匹配",权限值从 AMQ 6 类型映射到 AMQ 7 类型,角色映射为原样。由于 LDAP 中定义的队列或主题的名称充当安全设置匹配,因此安全性设置可能无法按预期应用到 JMS 目的地。这是因为 AMQ 7 始终将 JMS 目的地前缀为 "jms.queue." 或 "jms.topic.",根据需要。

AMQ 6 具有三种权限类型 - 读取写入和 admin。这些权限类型在 ActiveMQ 网站上描述; 安全

AMQ 7 有以下权限类型:

  • createAddress
  • deleteAddress
  • createDurableQueue
  • deleteDurableQueue
  • createNonDurableQueue
  • deleteNonDurableQueue
  • send
  • consume
  • 管理
  • browse

    下表显示了安全设置插件如何将 AMQ 6 权限类型映射到 AMQ 7 权限类型:

    AMQ 6 权限类型AMQ 7 权限类型

    读取

    使用、浏览

    write

    send

    admin

    createAddress, deleteAddress, createDurableQueue, deleteDurableQueue, createNonDurableQueue, deleteNonDurableQueue, manage(if mapAdminToManage is 设为 true

    如下所述,一些情况下,插件会在 AMQ 6 和 AMQ 7 权限类型之间进行一些转换,以实现等同于:

    • 映射默认不包含 AMQ 7 管理 权限类型,因为 AMQ 6 中没有类似权限类型。但是,如果 mapAdminToManage 设为 true,则插件会将 AMQ 6 admin 权限映射到 AMQ 7 管理权限
    • AMQ 6 中的 admin 权限类型决定代理是否自动创建目的地(如果目标不存在)以及向用户发送消息。如果用户有权限向目的地发送消息的权限,AMQ 7 会自动创建目的地。因此,插件默认将旧的 admin 权限映射到上方显示的 AMQ 7 权限。如果 mapAdminToManage 设为 true,则该插件也会将 AMQ 6 admin 权限映射到 AMQ 7 manage 权限。
allowQueueAdminOnRead

是否将旧的读取权限映射到 createDurableQueue、createNonDurableQueue 和 deleteDurableQueue 权限,以便 JMS 客户端可以创建持久的订阅,而无需 admin 权限。AMQ 6 中允许这一功能。默认值为 false。

下表显示了当 allowQueueAdminOnReadtrue 时,安全设置插件如何将 AMQ 6 权限类型映射到 AMQ 7 权限类型:

AMQ 6 权限类型AMQ 7 权限类型

读取

consume, browse, createDurableQueue, createNonDurableQueue, deleteDurableQueue

write

send

admin

createAddress, deleteAddress, deleteNonDurableQueue, manage(if mapAdminToManage 设为 true

5.4.3. 在 login.config 文件中加密密码

因为机构通常使用 LDAP 安全地存储数据,因此 login.config 文件可以包含代理与机构的 LDAP 服务器通信所需的配置。此配置文件通常包含登录 LDAP 服务器的密码,因此需要加密此密码。

先决条件

流程

以下流程演示了如何屏蔽 < broker_instance_dir> /etc/login.config 文件中找到的 connectionPassword 参数的值。

  1. 在命令提示符中,使用 mask 程序来加密密码:

    $ <broker_instance_dir>/bin/artemis mask <password>
    result: 3a34fd21b82bf2a822fa49a8d8fa115d
  2. 打开 & lt;broker_instance_dir&gt; /etc/login.config 文件。找到 connectionPassword 参数:

    connectionPassword = <password>
  3. 使用加密值替换 plain-text 密码:

    connectionPassword = 3a34fd21b82bf2a822fa49a8d8fa115d
  4. 使用标识符 "ENC()" 嵌套加密值:

    connectionPassword = "ENC(3a34fd21b82bf2a822fa49a8d8fa115d)"

login.config 文件现在包含已屏蔽的密码。由于密码以 "ENC()" 标识符进行嵌套,AMQ Broker 会在使用前对其进行解密。

其他资源

5.4.4. 映射外部角色

您可以将外部身份验证提供程序的角色(如 LDAP)映射到代理在内部使用的角色。

要映射外部角色,请在 broker.xml 配置文件中的 security-settings 元素中创建 role-mapping 条目。例如:

<security-settings>
...
    <role-mapping from="cn=admins,ou=Group,ou=ActiveMQ,ou=system" to="my-admin-role"/>
    <role-mapping from="cn=users,ou=Group,ou=ActiveMQ,ou=system" to="my-user-role"/>
</security-settings>
注意
  • 角色映射是可添加的。这意味着用户将保留原始角色以及新分配的角色。
  • 角色映射仅影响授权队列访问的角色,不提供启用 Web 控制台访问权限的方法。

5.5. 使用 Kerberos 进行身份验证和授权

使用 AMQP 协议发送和接收消息时,客户端可以使用 Simple Authentication and Security Layer (SASL)框架中的 GSSAPI 机制发送 Kerberos 安全凭证。Kerberos 凭据还可用于授权,方法是将经过身份验证的用户映射到在 LDAP 目录或基于文本的属性文件中配置的已分配角色。

您可以使用 SASL 和 传输层安全 (TLS)来保护您的消息传递应用程序。SASL 提供用户身份验证,并且 TLS 提供数据完整性。

重要

以下流程演示了如何配置用于身份验证和授权的 Kerberos。

5.5.1. 配置网络连接以使用 Kerberos

AMQ Broker 使用 简单身份验证和安全层 (SASL)框架中的 GSSAPI 机制与 Kerberos 安全凭证集成。要在 AMQ Broker 中使用 Kerberos,每个接受者验证或授权使用 Kerberos 凭证的客户端,都必须配置为使用 GSSAPI 机制。

以下流程演示了如何配置接受者使用 Kerberos。

先决条件

  • 在 AMQ Broker 可以验证和授权 Kerberos 凭证前,您必须部署和配置 Kerberos 基础架构。

流程

  1. 停止代理。

    1. 在 Linux 中:

      <broker_instance_dir>/bin/artemis stop
    2. 在 Windows 中:

      <broker_instance_dir>\bin\artemis-service.exe stop
  2. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  3. 将 name-value 对 saslMechanisms=GSSAPI 添加到 acceptor URL 的查询字符串。

    <acceptor name="amqp">
      tcp://0.0.0.0:5672?protocols=AMQP;saslMechanisms=GSSAPI
    </acceptor>

    上述配置意味着在验证 Kerberos 凭证时,接受者使用 GSSAPI 机制。

  4. (可选)还支持 PLAINANONYMOUS SASL 机制。要指定多个机制,请使用用逗号分开的列表。例如:

    <acceptor name="amqp">
      tcp://0.0.0.0:5672?protocols=AMQP;saslMechanisms=GSSAPI,PLAIN
    </acceptor>

    结果是使用 GSSAPIPLAIN SASL 机制的接受者。

  5. 启动代理。

    1. 在 Linux 中:

      <broker_instance_dir>/bin/artemis run
    2. 在 Windows 中:

      <broker_instance_dir>\bin\artemis-service.exe start

其他资源

5.5.2. 使用 Kerberos 凭证验证客户端

AMQ Broker 支持使用简单验证和安全层(SASL)框架中的 GSSAPI 机制的 AMQP 连接进行 Kerberos 验证

代理使用 Java 认证和授权服务(JAAS)获取其 Kerberos 接收器 凭证。Java 安装中包含的 JAAS 库通过登录模块 Krb5LoginModule 一起打包,用于验证 Kerberos 凭据。有关其 Krb5LoginModule 的更多信息,请参阅 Java 供应商中的文档。例如,Oracle 提供有关其 Krb5LoginModule 登录模块的信息,作为其 Java 8 文档 的一部分。

先决条件

流程

  1. 停止代理。

    1. 在 Linux 中:

      <broker_instance_dir>/bin/artemis stop
    2. 在 Windows 中:

      <broker_instance_dir>\bin\artemis-service.exe stop
  2. 打开 & lt;broker_instance_dir&gt; /etc/login.config 配置文件。
  3. 添加名为 amqp-sasl-gssapi 的配置范围。以下示例显示了在 JDK 和 JDK 版本中的 Krb5LoginModule 的配置。

    amqp-sasl-gssapi {
        com.sun.security.auth.module.Krb5LoginModule required
        isInitiator=false
        storeKey=true
        useKeyTab=true
        principal="amqp/my_broker_host@example.com"
        debug=true;
    };
    amqp-sasl-gssapi
    默认情况下,代理上的 GSSAPI 机制使用名为 amqp-sasl-gssapi 的 JAAS 配置范围来获取其 Kerberos 接受器凭证。
    Krb5LoginModule
    Krb5LoginModule 的这个版本由 JDK 和 OpenJDK 版本提供。通过引用 Java 供应商的文档来验证 Krb5LoginModule 及其可用选项的完全限定类名称。
    useKeyTab
    Krb5LoginModule 配置为在验证主体时使用 Kerberos keytab。使用 Kerberos 环境中的工具生成 keytab。有关生成 Kerberos keytab 的详情,请查看厂商中的文档。
    主体
    Principal 设置为 amqp/my_broker_host@example.com。这个值必须与 Kerberos 环境中创建的服务主体对应。有关创建服务主体的详情,请查看厂商中的文档。
  4. 启动代理。

    1. 在 Linux 中:

      <broker_instance_dir>/bin/artemis run
    2. 在 Windows 中:

      <broker_instance_dir>\bin\artemis-service.exe start
5.5.2.1. 使用替代配置范围

您可以通过在 AMQP 接受器的 URL 中添加参数 saslLoginConfigScope 来指定备选配置范围。在以下配置中,为参数 saslLoginConfigScope 提供值 alternative-sasl-gssapi。结果是使用名为 alternative-sasl-gssapi 的替代范围,在 < broker_instance_dir> /etc/login.config 配置文件中声明。

<acceptor name="amqp">
tcp://0.0.0.0:5672?protocols=AMQP;saslMechanisms=GSSAPI,PLAIN;saslLoginConfigScope=alternative-sasl-gssapi`
</acceptor>

5.5.3. 使用 Kerberos 凭证授权客户端

AMQ Broker 包括对 JAAS Krb5LoginModule 登录模块的实施,以便在映射角色时供其他安全模块使用。该模块将 Kerberos 验证的 Peer Principal 添加到 Subject 的主体集中为 AMQ Broker UserPrincipal。然后可将凭证传递给 PropertiesLoginModuleLDAPLoginModule 模块,它会将 Kerberos 验证的 Peer Principal Principal Principal 映射到 AMQ Broker 角色。

注意

Kerberos Peer Principal 不会以代理用户身份存在,仅作为角色成员。

先决条件

  • 您必须启用接收器的 GSSAPI 机制,然后才能使用 Kerberos 安全凭证授权 AMQP 连接。

流程

  1. 停止代理。

    1. 在 Linux 中:

      <broker_instance_dir>/bin/artemis stop
    2. 在 Windows 中:

      <broker_instance_dir>\bin\artemis-service.exe stop
  2. 打开 & lt;broker_instance_dir&gt; /etc/login.config 配置文件。
  3. 为 AMQ Broker Krb5LoginModuleLDAPLoginModule 添加配置。通过引用 LDAP 供应商中的文档来验证配置选项。

    下面是一个配置示例。

    org.apache.activemq.artemis.spi.core.security.jaas.Krb5LoginModule required
        ;
    org.apache.activemq.artemis.spi.core.security.jaas.LDAPLoginModule optional
        initialContextFactory=com.sun.jndi.ldap.LdapCtxFactory
        connectionURL="ldap://localhost:1024"
        authentication=GSSAPI
        saslLoginConfigScope=broker-sasl-gssapi
        connectionProtocol=s
        userBase="ou=users,dc=example,dc=com"
        userSearchMatching="(krb5PrincipalName={0})"
        userSearchSubtree=true
        authenticateUser=false
        roleBase="ou=system"
        roleName=cn
        roleSearchMatching="(member={0})"
        roleSearchSubtree=false
        ;
    注意

    上例中显示的 Krb5LoginModule 版本通过 AMQ Broker 分发,并将 Kerberos 身份转换为代理身份,供其他 AMQ 模块用于角色映射。

  4. 启动代理。

    1. 在 Linux 中:

      <broker_instance_dir>/bin/artemis run
    2. 在 Windows 中:

      <broker_instance_dir>\bin\artemis-service.exe start

其他资源

5.6. 指定安全管理器

代理使用名为 安全管理器 的组件来处理身份验证和授权。

AMQ Broker 包括两个安全管理器:

  • ActiveMQJAASSecurityManager 安全管理器。此安全管理器与红帽 JBoss 企业应用平台(JBoss EAP)安全性提供集成。这是 AMQ Broker 使用的默认安全管理器。
  • ActiveMQBasicSecurityManager 安全管理器。这个基本安全管理器不支持 JAAS。相反,它通过用户名和密码凭证支持身份验证和授权。此安全管理器支持使用管理 API 添加、删除和更新用户。所有用户和角色数据都存储在代理绑定日志中。这意味着对实时代理进行的任何更改都可用于备份代理。

作为包含安全管理器的替代选择,系统管理员可能希望更多地控制代理安全实施。在这种情况下,也可以在代理配置中指定 自定义 安全管理器。自定义安全管理器是一个用户定义的类,它实施 org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager5 接口。

以下子部分示例演示了如何配置要使用的代理:

  • 基本安全管理器,而不是默认的 JAAS 安全管理器
  • 自定义安全管理器

5.6.1. 使用基本安全管理器

除了默认的 ActiveMQJAASSecurityManager 安全管理器外,AMQ Broker 还还包括 ActiveMQBasicSecurityManager 安全管理器。

使用基本安全管理器时,所有用户和角色数据都存储在绑定日志中(如果您使用 JDBC 持久性,或者绑定 )。因此,如果您配置了 live-backup 代理组,则所有对实时代理的用户管理都会在故障切换时自动反映在备份代理中。这可避免单独管理 LDAP 服务器的需求,这是实现此行为的替代方式。

在配置和使用基本安全管理器前,请注意以下几点:

  • 基本的安全管理器不像默认的 JAAS 安全管理器那样插入。
  • 基本安全管理器不支持 JAAS。相反,它只支持通过用户名和密码凭证进行身份验证和授权。
  • AMQ 管理控制台需要 JAAS。因此,如果您使用基本安全管理器并希望使用控制台,您还需要为用户和密码身份验证配置 login.config 配置文件。有关配置用户和密码验证的详情,请参考 第 5.2.2.1 节 “配置基本用户和密码身份验证”
  • 在 AMQ Broker 中,用户管理由代理管理 API 提供。此管理包括添加、列表、更新和删除用户和角色的能力。您可以使用 JMX、管理消息、HTTP(使用 Jolokia 或 AMQ Management Console)和 AMQ Broker 命令行界面来执行这些功能。由于代理直接存储此数据,代理必须正在运行,以便管理用户。无法手动修改绑定数据。
  • 通过 HTTP 的任何管理访问(例如,使用 Jolokia 或 AMQ Management Console)由 console JAAS 登录模块处理。基本安全管理器处理通过 JConsole 或其他远程 JMX 工具的 MBean 访问。管理消息由基本安全管理器处理。
5.6.1.1. 配置基本安全管理器

以下流程演示了如何将代理配置为使用基本安全管理器。

流程

  1. 打开 & lt;broker-instance-dir&gt; /etc/boostrap.xml 配置文件。
  2. security-manager 元素中,在 class-name 属性中指定完整的 ActiveMQBasicSecurityManager 类名称。

    <broker xmlns="http://activemq.org/schema">
       ...
       <security-manager class-name="org.apache.activemq.artemis.spi.core.security.ActiveMQBasicSecurityManager">
       </security-manager>
       ...
    </broker>
  3. 因为您无法手动修改包含用户和角色数据的绑定数据,并且代理必须正在运行才能管理用户,建议在第一次引导时保护代理。要实现此目的,请定义 bootstrap 用户,该用户 随后可以使用其凭证来添加其他用户。

    security-manager 元素中,添加 bootstrapUserbootstrapPasswordbootstrapRole 属性并指定值。例如:

    <broker xmlns="http://activemq.org/schema">
       ...
       <security-manager class-name="org.apache.activemq.artemis.spi.core.security.ActiveMQBasicSecurityManager">
            <property key="bootstrapUser" value="myUser"/>
            <property key="bootstrapPassword" value="myPass"/>
            <property key="bootstrapRole" value="myRole"/>
       </security-manager>
       ...
    </broker>
    bootstrapUser
    bootstrap 用户的名称。
    bootstrapPassword
    boostrap 用户的 Passsword.您还可以指定加密的密码。
    bootstrapRole

    boostrap 用户的角色。

    注意

    如果您在配置中为 bootstrap 用户定义前面的属性,则每次启动代理时都会设置这些凭证,无论您在代理运行时所做的任何更改。

  4. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  5. broker.xml 配置文件中,找到 located .management# 地址 default 定义的 address-setting 元素。这些默认地址设置如下所示。

    <address-setting match="activemq.management#">
        <dead-letter-address>DLQ</dead-letter-address>
        <expiry-address>ExpiryQueue</expiry-address>
        <redelivery-delay>0</redelivery-delay>
        <!--...-->
        <max-size-bytes>-1</max-size-bytes>
        <message-counter-history-day-limit>10</message-counter-history-day-limit>
        <address-full-policy>PAGE</address-full-policy>
        <auto-create-queues>true</auto-create-queues>
        <auto-create-addresses>true</auto-create-addresses>
        <auto-create-jms-queues>true</auto-create-jms-queues>
        <auto-create-jms-topics>true</auto-create-jms-topics>
    </address-setting>
  6. activemq.management# 地址匹配项的地址设置中,对于您之前在此流程中指定的 bootstrap 角色名称,添加以下所需的权限:

    • createNonDurableQueue
    • createAddress
    • consume
    • 管理
    • send

    例如:

    <address-setting match="activemq.management#">
        ...
        <permission type="createNonDurableQueue" roles="myRole"/>
        <permission type="createAddress" roles="myRole"/>
        <permission type="consume" roles="myRole"/>
        <permission type="manage" roles="myRole"/>
        <permission type="send" roles="myRole"/>
    </address-setting>

其他资源

5.6.2. 指定自定义安全管理器

以下流程演示了如何在代理配置中指定自定义安全管理器。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/boostrap.xml 配置文件。
  2. security-manager 元素中,对于 class-name 属性,指定是 org.apache. office.artemis.spi.security.security.ActiveMQSecurityManager5 接口的用户定义的实施的类。例如:

    <broker xmlns="http://activemq.org/schema">
       ...
       <security-manager class-name="com.foo.MySecurityManager">
          <property key="myKey1" value="myValue1"/>
          <property key="myKey2" value="myValue2"/>
       </security-manager>
       ...
    </broker>

其他资源

5.6.3. 运行自定义安全管理器示例程序

AMQ Broker 包括一个示例程序,它演示了如何实施自定义安全管理器。在示例中,自定义安全管理器会记录身份验证和授权的详细信息,然后将详细信息传递给 ActiveMQJAASSecurityManager 实例(即默认安全管理器)。

以下流程演示了如何运行自定义安全管理器示例程序。

先决条件

  • 您的机器必须设置为运行 AMQ Broker 示例程序。如需更多信息,请参阅 运行 AMQ Broker 示例

流程

  1. 前往包含自定义安全管理器示例的目录。

    $ cd <install_dir>/examples/features/standard/security-manager
  2. 运行示例。

    $ mvn verify
注意

如果要在运行示例程序时手动创建和启动代理实例,请将上一步中的命令替换为 mvn -PnoServer verify

其他资源

5.7. 禁用安全性

安全性 默认为启用。以下流程演示了如何禁用代理安全性。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. core 元素中,将 security-enabled 的值设置为 false

    <security-enabled>false</security-enabled>
  3. 如果需要,为 security-invalidation-interval 指定一个新值(以毫秒为单位)。这个属性值指定代理定期出现安全登录的时间。默认值为 10000

5.8. 从验证用户跟踪信息

要启用跟踪并记录消息的来源(例如,对于安全审核),您可以使用 _AMQ_VALIDATED_USER 消息键。

broker.xml 配置文件中,如果 populate-validated-user 选项被设置为 true,则代理将使用 _AMQ_VALIDATED_USER 密钥将验证用户的名称添加到消息中。对于 JMS 和 STOMP 客户端,此消息会映射到 JMSXUserID 密钥。

注意

代理无法将验证的用户名添加到 AMQP JMS 客户端生成的消息中。在客户端发送了 AMQP 消息后,修改 AMQP 消息的属性违反了 AMQP 协议。

对于基于其/her SSL 证书验证的用户,由代理填充的验证用户名是证书的不同名称(DN)映射的名称。

broker.xml 配置文件中,如果启用 security-enabledfalse填充-validated-usertrue,则代理会填充任何用户名(若有),则代理会填充客户端提供的任何用户名。默认情况下,populate-validated-user 选项为 false

您可以将代理配置为拒绝没有用户名(即 JMSXUserID 密钥)在邮件中已经填充的消息。您可能会发现此选项对 AMQP 客户端很有用,因为代理无法为这些客户端发送的消息填充验证的用户名本身。

要将代理配置为拒绝客户端设定的 JMSXUserID,请在 broker.xml 配置文件中添加以下配置:

<reject-empty-validated-user>true</reject-empty-validated-user>

默认情况下,reject-empty-validated-user 设置为 false

5.9. 加密配置文件中的密码

默认情况下,AMQ Broker 将所有密码以纯文本形式存储在配置文件中。务必使用正确的权限保护所有配置文件,以防止未经授权的访问。您还可以加密或 屏蔽,即纯文本密码,以防止不需要的查看器读取它们。

5.9.1. 关于加密密码

加密的或 屏蔽,密码是纯文本密码的加密版本。加密的版本由 AMQ Broker 提供的 mask 命令行工具生成。有关 掩码 工具的更多信息,请参阅命令行帮助文档:

$ <broker_instance_dir>/bin/artemis help mask

要屏蔽密码,请将其纯文本值替换为加密的密码。屏蔽的密码必须由标识符 ENC() 嵌套,以便在需要实际值时解密它。

在以下示例中,配置文件 < broker_instance_dir>/etc/bootstrap.xml 包含 keyStorePasswordtrustStorePassword 参数的屏蔽密码。

<web bind="https://localhost:8443" path="web"
     keyStorePassword="ENC(-342e71445830a32f95220e791dd51e82)"
     trustStorePassword="ENC(32f94e9a68c45d89d962ee7dc68cb9d1)">
    <app url="activemq-branding" war="activemq-branding.war"/>
</web>

您可以将屏蔽的密码与以下配置文件搭配使用。

  • broker.xml
  • bootstrap.xml
  • management.xml
  • artemis-users.properties
  • login.config(用于 LDAPLoginModule

配置文件位于 < broker_instance_dir> /etc

注意

pata-users.properties 支持仅屏蔽已哈希化的密码。在创建代理时创建用户时,artemis-users.properties 默认包含哈希密码。默认 PropertiesLoginModule 不会解码 artemis-users.properties 文件中的密码,而是会将输入散列化,并比较两个散列值以进行密码验证。将散列密码更改为掩码的密码不允许访问 AMQ Broker 管理控制台。

broker.xmlbootstrap.xmlmanagement.xmllogin.config 支持屏蔽但未哈希的密码。

5.9.2. 在配置文件中加密密码

以下示例演示了如何在 broker.xml 配置文件中屏蔽 cluster-password 的值。

流程

  1. 在命令提示符中,使用 mask 程序来加密密码:

    $ <broker_instance_dir>/bin/artemis mask <password>
    result: 3a34fd21b82bf2a822fa49a8d8fa115d
  2. 打开 & lt;broker_instance_dir> /etc/broker.xml 配置文件,其中包含您要屏蔽的纯文本密码:

    <cluster-password>
      <password>
    </cluster-password>
  3. 使用加密值替换 plain-text 密码:

    <cluster-password>
      3a34fd21b82bf2a822fa49a8d8fa115d
    </cluster-password>
  4. 使用标识符 ENC() 嵌套加密值:

    <cluster-password>
      ENC(3a34fd21b82bf2a822fa49a8d8fa115d)
    </cluster-password>

配置文件现在包含加密的密码。由于密码使用 ENC() 标识符进行嵌套,AMQ Broker 会在使用前对其进行解密。

其他资源

5.9.3. 设置 codec 密钥以加密和解密密码

需要使用 codec 来加密和解密密码。如果没有配置自定义 codec,掩码实用程序会 使用默认 codec 来加密密码和 AMQ Broker 使用相同的默认 codec 来解密密码。codec 配置了一个默认密钥,它提供给底层加密算法以加密和解密密码。使用默认密钥会带来风险,恶意人员可能曾使用该密钥来解密您的密码。

当您使用 掩码 实用程序加密密码时,您可以指定自己的密钥字符串以避免使用默认的 codec 键。然后,您必须在 ARTEMIS_DEFAULT_SENSITIVE_STRING_CODEC_KEY 环境变量中设置相同的字符串,以便代理可以解密密码。在环境变量中设置密钥会使它更安全,因为它不会保留在配置文件中。另外,您可以在启动代理前立即设置密钥,并在代理启动后立即设置它。

流程

  1. 使用 mask 实用程序加密配置文件中的每个密码。对于 key 参数,指定用于加密密码的字符串。使用相同的密钥字符串来加密各个密码。

    $ <broker_instance_dir>/bin/artemis mask --key <key> <password>
    警告

    确保您在运行 掩码 实用程序加密密码时指定的 key 字符串记录。您必须在环境变量中配置相同的键值,以允许代理解密密码。

    有关在配置文件中加密密码的详情请参考 第 5.9.2 节 “在配置文件中加密密码”

  2. 在命令提示符中,将 ARTEMIS_DEFAULT_SENSITIVE_STRING_CODEC_KEY 环境变量设置为您在每个密码加密时指定的密钥字符串。

    $ export ARTEMIS_DEFAULT_SENSITIVE_STRING_CODEC_KEY= <key>
  3. 启动代理。

    $ ./artemis run
  4. 取消设置 ARTEMIS_DEFAULT_SENSITIVE_STRING_CODEC_KEY 环境变量。

    $ unset ARTEMIS_DEFAULT_SENSITIVE_STRING_CODEC_KEY
    注意

    如果您在启动代理后取消设置 ARTEMIS_DEFAULT_SENSITIVE_STRING_CODEC_KEY 环境变量,则必须在后续时间启动代理前将其重新设置为同一密钥字符串。

第 6 章 持久性消息数据

对于持久性( storing)消息数据,AMQ Broker 有两个选项。

在日志中保留消息
这是默认选项。基于日志的持久性是一个高性能选项,可将消息写入文件系统中的日志。
在数据库中保留消息
这个选项使用 Java 数据库连接 (JDBC)连接将消息持久化到您选择的数据库。

另外,您还可以配置代理 不会保留 任何消息数据。更多信息请参阅 第 6.3 节 “禁用持久性”

代理使用不同的解决方案来保留消息日志外的大型消息。如需更多信息,请参阅 第 8 章 处理大型消息

代理也可以配置为以低内存情况下将消息输出到磁盘。如需更多信息,请参阅 第 7.1 节 “配置消息分页”

注意

有关 AMQ Broker 支持哪些数据库和网络文件系统的当前信息,请参阅红帽客户门户网站中的 Red Hat AMQ 7 支持的配置

6.1. 在日志中保留消息数据

代理日志是 磁盘上的一组只读文件。每个文件已预先创建为固定大小,最初使用 padding 进行填充。当消息操作在代理上执行时,记录会附加到日志的末尾。附加记录可让代理最小化磁盘头移动和随机访问操作,这通常是磁盘上的最慢的操作。当一个日志文件已满时,代理会创建一个新日志文件。

日志文件的大小可以配置,尽量减少每个文件使用的磁盘柱面的数量。现代磁盘拓扑比较复杂,但代理无法控制文件映射到的柱面。因此,日志文件大小很难精确控制。

代理使用的其他持久性功能包括:

  • 确定特定日志文件是否仍然在使用的 垃圾回收 算法。如果日志文件不再使用,则代理可以回收该文件以重复使用。
  • 从日志中删除死空间的压缩算法,并压缩数据。这会生成磁盘上使用较少的文件的日志。
  • 支持本地事务。
  • 在使用 JMS 客户端时支持扩展架构(XA)事务。

大多数日志都是以 Java 编写的。但是,使用与实际文件系统的交互是抽象的,因此您可以使用不同的可插入的实现。AMQ Broker 包括以下实现:

NIO
NIO(新 I/O)使用标准 Java NIO 与文件系统接口。这可提供极好的性能,并在具有 Java 6 或更高版本运行时的任何平台上运行。有关 Java NIO 的更多信息,请参阅 Java NIO
AIO

AIO(Aynshcronous I/O)使用精简原生打包程序与 Linux Asynchronous I/O 库(libaio)对话。使用 AIO 时,在数据提供给磁盘后代理会重新调用,从而避免了显式同步。默认情况下,代理尝试使用 AIO 日志,如果 AIO 不可用,代理将回退到使用 NIO。

AIO 的性能优于 Java NIO。要了解如何安装 libaio,请参阅 第 6.1.1 节 “安装 Linux 同步 I/O 库”

以下的子部分中的步骤演示了如何为基于日志的持久性配置代理。

6.1.1. 安装 Linux 同步 I/O 库

红帽建议使用 AIO 日志(而不是 NIO)来改进持久性性能。

注意

无法与其他操作系统或早期版本的 Linux 内核一起使用 AIO 日志。

要使用 AIO 日志,您必须安装 Linux Asynchronous I/O 库(libaio)。要安装 libaio,请使用 yum 命令,如下所示:

yum install libaio

6.1.2. 配置基于日志的持久性

以下流程描述了如何查看代理用于基于日志的持久性的默认配置。您可以使用此描述根据需要调整配置。

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。

    默认情况下,代理配置为使用基于日志的持久性,如下所示。

    <configuration>
      <core>
        ...
        <persistence-enabled>true</persistence-enabled>
        <journal-type>ASYNCIO</journal-type>
        <bindings-directory>./data/bindings</bindings-directory>
        <journal-directory>./data/journal</journal-directory>
        <journal-datasync>true</journal-datasync>
        <journal-min-files>2</journal-min-files>
        <journal-pool-files>-1</journal-pool-files>
        <journal-device-block-size>4096</journal-device-block-size>
        <journal-file-size>10M</journal-file-size>
        <journal-buffer-timeout>12000</journal-buffer-timeout>
        <journal-max-io>4096</journal-max-io>
        ...
      </core>
    </configuration>
    启用持久性
    如果此参数的值设置为 true,代理将使用基于文件的日志进行消息持久性。
    journal-type
    要使用的日志类型。如果设置为 ASYNCIO,则代理首先尝试使用 AIO。如果没有找到 AIO,代理将使用 NIO。
    bindings-directory
    绑定日志的文件系统位置。默认值相对于 < broker_instance_dir> 目录。
    journal-directory
    消息日志的文件系统位置。默认值相对于 < broker_instance_dir> 目录。
    journal-datasync
    如果此参数的值被设置为 true,则代理将使用 fdatasync 功能来确认磁盘写入。
    journal-min-files
    代理启动时首先创建的日志文件数。
    journal-pool-files
    回收未使用的文件后要保留的文件数。默认值 -1 表示清理过程中不会删除任何文件。
    journal-device-block-size
    存储设备上日志使用的数据块的最大大小,以字节为单位。默认值为 4096 字节。
    journal-file-size
    指定日志目录中每个日志文件的最大大小,以字节为单位。当达到这个限制时,代理会启动一个新文件。这个参数还支持字节表示法(例如 K、M、G)或二进制等同的(Ki、Mi、Gi)。如果未在配置中明确指定此参数,则默认值为 10485760 字节(10MiB)。
    journal-buffer-timeout
    指定日志缓冲区的频率(以纳秒为单位)。AIO 通常使用高于 NIO 的冲刷率,因此代理会维护 NIO 和 AIO 的不同默认值。如果未在配置中明确指定此参数,则 NIO 的默认值是 3333333 纳秒(每秒 300 次)。AIO 的默认值为 50000 纳秒(即每秒 2000 倍)。
    journal-max-io

    在任何时间点上,可在 IO 队列中每个写入请求数上限。如果队列已满,代理将阻止进一步写入,直到空间可用为止。

    如果您使用的是 NIO,这个值应该始终为 1。如果您使用 AIO 和这个参数在配置中没有指定,则默认值为 500

  2. 根据前面的描述,根据需要调整存储设备的持久性配置。

其他资源

6.1.3. 关于绑定日志

绑定日志用于存储与绑定相关的数据,如代理上部署的一组队列及其属性。它还存储数据,如 ID 序列计数器。

绑定日志始终使用 NIO,因为它在与消息日志相比通常会较低吞吐量。此日志上的文件以 activemq-bindings 为前缀。每个文件也具有 .bindings 的扩展,以及默认大小为 1048576 字节。

要配置绑定日志,请在 < broker_instance_dir&gt; /etc/broker.xml 配置文件的 核心元素 中包含以下参数。

bindings-directory
绑定日志的目录。默认值为 < broker_instance_dir>/data/bindings
create-bindings-dir
如果此参数的值被设置为 true,代理会自动在绑定目录中指定的位置(如果 绑定目录 )中创建绑定目录 (如果不存在)。默认值为 true

6.1.4. 关于 JMS 日志

JMS 日志存储所有 JMS 相关数据,包括 JMS 队列、主题和连接工厂,以及这些资源的任何 JNDI 绑定。通过管理 API 创建的任何 JMS 资源都保留在此日志中,但通过配置文件配置的任何资源都不是。只有在使用 JMS 时,代理才会创建 JMS 日志。

JMS 日志中的文件前缀为 activemq-jms。每个文件也有 .jms 的扩展,默认大小为 1048576 字节。

JMS 日志通过绑定日志共享其配置。

其他资源

6.1.5. 配置日志保留

您可以配置 AMQ Broker 来保留创建的每个日志文件的副本。配置日志保留后,您可以在日志文件中重新显示消息,以将消息发送到代理。

6.1.5.1. 配置日志保留

您可以将 AMQ Broker 配置为在特定时间段内或同时达到存储限制前保留日志文件副本。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. core 元素内,添加 journal-retention-directory 属性。指定 periodstorage-limit,或同时指定控制日志文件的保留。另外,为日志文件副本指定文件系统位置。以下示例配置 AMQ Broker,以在 data/retention 目录中保留日志文件副本 7 天,或直到文件使用 10GB 的存储。
<configuration>
  <core>
    ...
    <journal-retention-directory period="7" unit="DAYS" storage-limit="10G">data/retention</journal-retention-directory>
    ...
  </core>
</configuration>
周期
保存日志文件副本的时间周期。当时间到期时,AMQ Broker 将删除超过指定时间段内的任何文件。
unit
应用到保留周期的测量单位。默认值为 DAYS。其他有效值为 HOURSMINUTESSECONDS
目录
日志文件副本的文件系统位置。指定的目录相对于 < broker_instance_dir> 目录。
storage-limit
所有日志文件副本可以使用的最大存储。如果达到存储限制,代理会删除最旧的日志文件,以便为新的日志文件副本提供空间。设置存储限制是确保日志文件保留不会导致代理耗尽磁盘空间和关闭的有效方法。
6.1.5.2. 在日志文件副本中重播消息复制中的地址

如果要从 AMQ Broker 上的日志文件副本中重播的信息地址,请使用以下步骤重现信息。您可以将消息重新显示到代理上的原始地址或不同地址。

流程

  1. 登录 AMQ 管理控制台。如需更多信息,请参阅 访问 AMQ 管理控制台
  2. 在主菜单中,单击 Artemis
  3. 在文件夹树中,单击 地址 以显示地址列表。
  4. 地址 选项卡。
  5. 在您要重播消息的地址的 Action 列中,单击 操作
  6. 选择 replay 操作。

    • 如果您希望 replay 操作搜索所有日志文件副本中的消息重播,点 replay (String,String) 操作。
    • 如果您希望 replay 操作搜索仅在特定时间段内创建的日志文件副本中的消息重播,请选择 replay (String,String,String) 操作。在 startScanDateendScanDate 字段中指定 period。
  7. 指定 replay 选项。

    1. target 字段中,指定代理上要发送重播消息的地址。如果将此字段留空,则消息会重新显示到代理上的原始地址。
    2. (可选)在 过滤器 字段中,指定一个字符串来只重播与过滤器字符串匹配的消息。例如,如果消息具有 storeID 属性,您可以使用 storeID="1000" 过滤来回放所有存储 ID 值为 1000 的消息。如果您没有指定过滤器,扫描的日志文件副本中的所有信息都会重播到 AMQ Broker。
  8. Execute

其他资源

6.1.5.3. 在日志文件复制中重播从代理中删除的地址

如果要从 journal 文件副本重新显示的信息地址已从 AMQ Broker 中删除,请使用以下步骤将消息回放到代理上的不同地址。

流程

  1. 登录 AMQ 管理控制台。如需更多信息,请参阅 访问 AMQ 管理控制台
  2. 在主菜单中,单击 Artemis
  3. 在文件夹树中,单击顶级服务器。
  4. 单击 运营 选项卡。
  5. 选择 replay 操作。

    • 如果您希望 replay 操作搜索所有日志文件副本中的消息重播,点 replay (String,String,String) 操作。
    • 如果您希望 replay 操作搜索仅在特定时间段内创建的日志文件副本中的消息重播,请选择 replay (String,String,String,String) 操作。在 startScanDateendScanDate 字段中指定 period。
  6. 指定 replay 选项。

    1. address 字段中,指定要重播的消息地址。
    2. target 字段中,指定代理上要发送重播消息的地址。
    3. (可选)在 过滤器 字段中,指定一个字符串来只重播与过滤器字符串匹配的消息。例如,如果消息具有 storeID 属性,您可以使用 storeID="1000" 过滤来回放所有存储 ID 值为 1000 的消息。如果您没有指定过滤器,扫描的日志文件副本中的所有信息都会重播到 AMQ Broker。
  7. Execute

其他资源

6.1.6. 模拟日志文件

AMQ Broker 包括一个压缩算法,从日志中删除死空间并压缩数据,使其占用较少的磁盘空间。

以下子部分演示了如何:

6.1.6.1. 配置日志文件压缩

代理使用以下条件来决定何时启动压缩:

  • 为日志创建的文件数量。
  • 日志文件中实时数据的百分比。

在满足这两个条件的配置值后,压缩过程会解析日志并删除所有死记录。因此,日志包含较少的文件。

以下流程演示了如何为日志文件压缩配置代理。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. core 元素中,添加 journal-compact-min-filesjournal-compact-percentage 参数并指定值。例如:

    <configuration>
      <core>
        ...
        <journal-compact-min-files>15</journal-compact-min-files>
        <journal-compact-percentage>25</journal-compact-percentage>
        ...
      </core>
    </configuration>
    journal-compact-min-files
    代理在压缩开始前必须创建的最小日志文件数量。默认值为 10。将值设为 0 可禁用压缩。您应该在禁用压缩时要小心,因为日志的大小可以无限期地增加。
    journal-compact-percentage
    日志文件中实时数据的百分比。当少于此百分比时(以及已达到 journal-compact-min-files 的配置值)开始压缩。默认值为 30
6.1.6.2. 从命令行界面运行压缩

以下流程演示了如何使用命令行界面(CLI)紧凑日志文件。

流程

  1. 作为 < broker_instance_dir&gt; 目录的所有者,停止代理。以下示例显示了用户 amq-broker

    su - amq-broker
    cd <broker_instance_dir>/bin
    $ ./artemis stop
  2. (可选)运行以下 CLI 命令来获取数据工具的完整参数列表。默认情况下,该工具使用 < broker_instance_dir> /etc/broker.xml 中找到的设置。

    $ ./artemis help data compact.
  3. 运行以下 CLI 命令以紧凑数据。

    $ ./artemis data compact.
  4. 在工具成功压缩数据后,重启代理。

    $ ./artemis run

其他资源

  • AMQ Broker 包含多个用于管理日志文件的 CLI 命令。如需更多信息,请参阅附录中的命令行工具

6.1.7. 禁用磁盘写入缓存

大多数磁盘包含硬件写入缓存。写入缓存可能会增加磁盘的明显性能,因为写入操作稍后被写入磁盘。默认情况下,许多系统随附启用了磁盘写入缓存。这意味着即使在从操作系统同步后,也无法保证数据实际上已经设为磁盘。因此,如果发生故障,关键数据可能会丢失。

有些昂贵的磁盘具有非易变或者有电池的写入缓存,它们不一定会在失败时丢失数据,但您应该对其进行测试。如果您的磁盘没有这样的功能,您应该确保已禁用写入缓存。请注意,禁用磁盘写入缓存可能会对性能造成负面影响。

以下流程演示了如何在 Windows 上的 Linux 中禁用磁盘写入缓存。

流程

  1. 在 Linux 上,要管理磁盘写入缓存设置,请使用工具 hdparm (用于 IDE 磁盘)或 sdparmsginfo (用于 SDSI/SATA 磁盘)。
  2. 在 Windows 上,要管理磁盘写器缓存设置,请右键点击磁盘。选择 属性

6.2. 在数据库中保留消息数据

当您将消息数据保存在数据库中时,代理使用 Java 数据库连接 (JDBC)连接将消息和绑定数据存储在数据库表中。表中的数据使用 AMQ Broker 日志编码的。有关支持的数据库的详情,请查看红帽客户门户网站中的 Red Hat AMQ 7 支持的配置

重要

管理员可能会根据组织更广的 IT 基础架构的要求,将消息数据存储在数据库中。但是,使用数据库可能会对消息传递系统的性能造成负面影响。具体来说,通过 JDBC 将消息传递数据写入数据库表可显著提高代理的性能开销。

6.2.1. 配置 JDBC 持久性

以下流程演示了如何配置代理以在数据库表中存储消息和绑定数据。

流程

  1. 将适当的 JDBC 客户端库添加到代理运行时。要做到这一点,将相关的 .jar 文件添加到 < broker_instance_dir>/lib 目录中。
  2. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  3. core 元素中,添加一个包含 database-store 元素的 store 元素。

    <configuration>
      <core>
        <store>
           <database-store>
           </database-store>
        </store>
      </core>
    </configuration>
  4. database-store 元素中,为 JDBC 持久性添加配置参数并指定值。例如:

    <configuration>
      <core>
        <store>
           <database-store>
              <jdbc-connection-url>jdbc:oracle:data/oracle/database-store;create=true</jdbc-connection-url>
              <jdbc-user>ENC(5493dd76567ee5ec269d11823973462f)</jdbc-user>
              <jdbc-password>ENC(56a0db3b71043054269d11823973462f)</jdbc-password>
              <bindings-table-name>BIND_TABLE</bindings-table-name>
              <message-table-name>MSG_TABLE</message-table-name>
              <large-message-table-name>LGE_TABLE</large-message-table-name>
              <page-store-table-name>PAGE_TABLE</page-store-table-name>
              <node-manager-store-table-name>NODE_TABLE</node-manager-store-table-name>
              <jdbc-driver-class-name>oracle.jdbc.driver.OracleDriver</jdbc-driver-class-name>
              <jdbc-network-timeout>10000</jdbc-network-timeout>
              <jdbc-lock-renew-period>2000</jdbc-lock-renew-period>
              <jdbc-lock-expiration>20000</jdbc-lock-expiration>
              <jdbc-journal-sync-period>5</jdbc-journal-sync-period>
           </database-store>
        </store>
      </core>
    </configuration>
    jdbc-connection-url
    您的数据库服务器的完整 JDBC 连接 URL。连接 URL 应包含所有配置参数和数据库名称。
    jdbc-user
    您的数据库服务器的加密用户名。有关加密用户名和密码以便在配置文件中使用的详情,请参考 第 5.9 节 “加密配置文件中的密码”
    jdbc-password
    您的数据库服务器的加密密码。有关加密用户名和密码以便在配置文件中使用的详情,请参考 第 5.9 节 “加密配置文件中的密码”
    bindings-table-name
    存储绑定数据的表名称。指定表名称允许您在多个服务器之间共享单个数据库,而无需干预。
    message-table-name
    存储消息数据的表名称。指定此表名称允许您在多个服务器之间共享单个数据库,而无需干预。
    large-message-table-name
    大型消息和相关数据的表的名称被保留。另外,如果客户端以块形式发送大量消息,则该块存储在此表中。指定此表名称允许您在多个服务器之间共享单个数据库,而无需干预。
    page-store-table-name
    保存用于存储目录信息的表名称。指定此表名称允许您在多个服务器之间共享单个数据库,而无需干预。
    node-manager-store-table-name
    用于实时和备份代理的共享存储高可用性(HA)锁定表的名称,其他与 HA 相关的数据存储在代理服务器上。指定此表名称允许您在多个服务器之间共享单个数据库,而无需干预。使用共享存储 HA 的每个 live-backup 对都必须使用相同的表名称。您不能在多个(和不相关)实时备份对之间共享相同的表。
    jdbc-driver-class-name
    JDBC 数据库驱动程序的完全限定类名称。有关支持的数据库的详情,请查看红帽客户门户网站中的 Red Hat AMQ 7 支持的配置
    jdbc-network-timeout
    JDBC 网络连接超时,以毫秒为单位。默认值为 20000 毫秒。将 JDBC 用于共享存储 HA 时,建议将超时设置为小于或等于 jdbc-lock-expiration
    jdbc-lock-renew-period
    当前 JDBC 锁定续订周期的长度(以毫秒为单位)。当这段时间时,代理可以续订锁定。建议设置一个小于 jdbc-lock-expiration 的值所小的值的值。这可让代理有足够的时间来扩展租期,并让代理时间在连接问题时尝试更新锁定。默认值为 2000 毫秒。
    jdbc-lock-expiration

    时间(以毫秒为单位),当前 JDBC 锁定被视为拥有(即被获取或续订),即使 jdbc-lock-renew-period 的值已过。

    代理定期尝试续订其根据 jdbc-lock-renew-period 值拥有的锁定。如果代理 无法更新 锁定(例如,由于连接问题),代理会不断尝试续订锁定,直到 jdbc-lock-expiration 的值不断被传递,因为锁定被上次成功获取或续订。

    上述续订行为的例外是另一个代理获取锁定。如果数据库管理系统(DBMS)和代理之间有时间错误,或者出现长时间暂停垃圾回收,则会出现这种情况。在这种情况下,最初拥有的锁定的代理会考虑锁定丢失,且不会尝试续订它。

    过期时间后,如果 JDBC 锁定没有被当前拥有它的代理续订,另一个代理可以建立 JDBC 锁定。

    jdbc-lock-expiration 默认值为 20000 毫秒。

    jdbc-journal-sync-period
    代理日志与 JDBC 同步的时间(以毫秒为单位)。默认值为 5 毫秒。

6.2.2. 配置 JDBC 连接池

如果您已经为 JDBC 持久性配置了代理,代理将使用 JDBC 连接在数据库表中存储消息和绑定数据。

如果出现 JDBC 连接失败,并且只要故障发生时没有活动连接活动(如数据库读取或写入),代理会继续运行,并尝试重新建立数据库连接。为了达到此目的,AMQ Broker 使用 JDBC 连接池

通常,连接池 提供一组对指定数据库的打开连接,这些连接可在多个应用程序之间共享。对于代理,如果代理和数据库间的连接失败,代理会尝试使用与池中不同的连接重新连接到数据库。该池在代理接收前测试新连接。

以下示例演示了如何配置 JDBC 连接池。

重要

如果您没有显式配置 JDBC 连接池,代理将使用具有默认配置的连接池。默认配置使用您现有的 JDBC 配置中的值。如需更多信息,请参阅 默认连接池配置

先决条件

流程

  1. 打开 & lt;broker-instance-dir&gt; /etc/broker.xml 配置文件。
  2. 在您之前为 JDBC 配置中添加的 database-store 元素中,删除 jdbc-driver-class-name jdbc-connection-urljdbc-userjdbc-password 和 参数。稍后,您将把它们替换为对应的 DBCP 配置参数。

    注意

    如果您没有显式删除上述参数,则稍后添加的对应 DBCP 参数具有优先权。

  3. database-store 元素中添加 data-source-properties 元素。例如:

    <store>
        <database-store>
            <data-source-properties>
            </data-source-properties>
            <bindings-table-name>BINDINGS</bindings-table-name>
            <message-table-name>MESSAGES</message-table-name>
            <large-message-table-name>LARGE_MESSAGES</large-message-table-name>
            <page-store-table-name>PAGE_STORE</page-store-table-name>
            <node-manager-store-table-name>NODE_MANAGER_STORE</node-manager-store-table-name>
            <jdbc-network-timeout>10000</jdbc-network-timeout>
            <jdbc-lock-renew-period>2000</jdbc-lock-renew-period>
            <jdbc-lock-expiration>20000</jdbc-lock-expiration>
            <jdbc-journal-sync-period>5</jdbc-journal-sync-period>
        </database-store>
    </store>
  4. 在新的 data-source-properties 元素中,为连接池添加 DBCP 数据源属性。指定键值对。例如:

    <store>
        <database-store>
            <data-source-properties>
                <data-source-property key="driverClassName" value="com.mysql.jdbc.Driver" />
                <data-source-property key="url" value="jdbc:mysql://localhost:3306/artemis" />
                <data-source-property key="username" value="ENC(5493dd76567ee5ec269d1182397346f)"/>
                <data-source-property key="password" value="ENC(56a0db3b71043054269d1182397346f)"/>
                <data-source-property key="poolPreparedStatements" value="true" />
                <data-source-property key="maxTotal" value="-1" />
            </data-source-properties>
            <bindings-table-name>BINDINGS</bindings-table-name>
            <message-table-name>MESSAGES</message-table-name>
            <large-message-table-name>LARGE_MESSAGES</large-message-table-name>
            <page-store-table-name>PAGE_STORE</page-store-table-name>
            <node-manager-store-table-name>NODE_MANAGER_STORE</node-manager-store-table-name>
            <jdbc-network-timeout>10000</jdbc-network-timeout>
            <jdbc-lock-renew-period>2000</jdbc-lock-renew-period>
            <jdbc-lock-expiration>20000</jdbc-lock-expiration>
            <jdbc-journal-sync-period>5</jdbc-journal-sync-period>
        </database-store>
    </store>
    driverClassName
    JDBC 数据库驱动程序的完全限定类名称。
    url
    您的数据库服务器的完整 JDBC 连接 URL。
    username
    您的数据库服务器的加密用户名。您还可以将这个值指定为未加密的纯文本。有关加密用户名和密码以便在配置文件中使用的详情,请参考 第 5.9 节 “加密配置文件中的密码”
    password
    您的数据库服务器的加密密码。您还可以将这个值指定为未加密的纯文本。有关加密用户名和密码以便在配置文件中使用的详情,请参考 第 5.9 节 “加密配置文件中的密码”
    poolPreparedStatements
    当此参数的值设置为 true 时,池可以无限数量的缓存语句。这降低了初始化成本。
    maxTotal
    池中连接的最大数量。当此参数的值设置为 -1 时,没有限制。

如果您没有显式配置 JDBC 连接池,代理将使用具有默认配置的连接池。默认配置在表中描述。

表 6.1. 默认连接池配置
DBCP 配置参数默认值

driverClassName

现有 jdbc-driver-class-name 参数的值

url

现有 jdbc-connection-url 参数的值

username

现有 jdbc-user 参数的值

password

现有 jdbc-password 参数的值

poolPreparedStatements

true

maxTotal

-1

注意

只有当 没有客户端主动向代理发送信息时,Reconnection 才有效。如果在重新连接过程中试图写入数据库表,代理会失败并关闭。

其他资源

6.3. 禁用持久性

在某些情况下,可能需要消息传递系统 不存储 任何数据。在这些情况下,您可以在代理中禁用持久性。

以下流程演示了如何禁用持久性。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. core 元素中,将 persistence-enabled 参数的值设置为 false

    <configuration>
      <core>
        ...
        <persistence-enabled>false</persistence-enabled>
        ...
      </core>
    </configuration>

    没有消息数据、绑定数据、大量消息数据、重复的 ID 缓存或分页数据保留。

第 7 章 为地址配置最大内存用量

AMQ Broker 以透明方式支持包含数百万消息的大量队列,即使托管代理的机器在内存有限的情况下运行。

在这些情况下,可能不会一次将所有队列存储在内存中。要防止过量内存消耗,您可以配置代理上每个地址允许的最大内存用量。另外,您可以指定当给定地址达到这个限制时代理执行的操作。

特别是,当地址的内存用量达到配置的限制时,您可以将代理配置为执行以下操作之一:

  • 页面信息
  • 静默丢弃信息
  • 丢弃消息并通知发送客户端
  • 阻止客户端发送消息

下面的部分演示了如何为地址配置最大内存用量,以及代理在达到地址限制时可以执行的操作。

重要

当您使用事务时,代理可能会分配额外的内存以确保事务一致性。在这种情况下,代理报告的内存用量可能无法反映内存中使用的字节数。因此,如果您将代理配置为页面、丢弃或阻止基于指定最大内存用量的消息,则不应该使用事务。

7.1. 配置消息分页

对于指定了最大内存用量限制的任何地址,您还可以指定达到该用量限制时代理要执行的操作。您可以配置的其中一个选项是 分页

如果您配置分页选项,当达到最大地址大小时,代理会开始将磁盘上的该地址的信息存储在称为 页面文件的文件中。每个页面文件具有您配置的最大大小。您以这种方式配置的每个地址在文件系统中都有一个专用文件夹来存储页面信息。

在检查队列中的消息时,队列浏览器和消费者都可以通过页面文件导航。但是,使用非常特定过滤器的使用者可能无法使用存储在页面文件中的消息,直到队列中的现有消息被消耗。例如,假设消费者过滤器包含字符串表达式,如 "color='red'"。如果满足此条件的消息遵循一百万带有属性 "color='blue'" 的消息,则消费者无法使用消息,直到消息中 "color='blue'" 已被使用。

当客户端就绪使用时,代理传输(即,depages)消息从磁盘变为内存中。当确认了该文件中的所有消息时,代理会从磁盘中删除页面文件。

下面的步骤演示了如何配置消息分页。

7.1.1. 指定分页目录

以下流程演示了如何指定分页目录的位置。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. core 元素中添加 pages -directory 元素。在文件系统中为分页目录指定一个位置。

    <configuration ...>
      <core ...>
        ...
        <paging-directory>/path/to/paging-directory</paging-directory>
        ...
      </core>
    </configuration>

    对于您随后为分页配置的每个地址,代理会在您指定的分页目录中添加一个专用目录。

7.1.2. 为分页配置地址

以下流程演示了如何为分页配置地址。

先决条件

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 对于您为匹配地址 或一组 地址配置的 address-setting 元素,添加配置元素以指定最大内存用量并定义分页行为。例如:

    <address-settings>
        <address-setting match="my.paged.address">
            ...
            <max-size-bytes>104857600</max-size-bytes>
            <page-size-bytes>10485760</page-size-bytes>
            <address-full-policy>PAGE</address-full-policy>
            ...
        </address-setting>
    </address-settings>
    max-size-bytes
    在代理执行为 address-full-policy 指定的策略前,地址允许的内存的最大大小(以字节为单位)。默认值为 -1,这表示没有限制。您指定的值还支持字节表示法,如"K"、"MB"和"GB"。
    page-size-bytes
    分页系统中使用的每个页面文件的大小(以字节为单位)。默认值为 10485760 (即 10 MiB)。您指定的值还支持字节表示法,如"K"、"MB"和"GB"。
    address-full-policy

    然后,达到地址的最大大小时代理要执行的操作。默认值为 PAGE。有效值为:

    页面
    代理将任何进一步的信息输出到磁盘。
    DROP
    代理会静默丢弃任何进一步的信息。
    FAIL
    代理会丢弃任何进一步的消息和问题例外,以客户端消息制作者。
    BLOCK
    客户端消息制作者在尝试发送更多消息时会阻断。

    上例中 未显示 的其他分页配置元素如下所述。

    page-max-cache-size
    代理保留在内存中的页面文件数量,以便在分页导航期间优化 IO。默认值为 5
    page-sync-timeout
    定期页面同步之间的时间(以纳秒为单位)。如果您使用异步 IO 日志(即,在 broker.xml 配置文件中将 journal-type 设为 ASYNCIO ),则默认值为 3333333。如果您使用标准的 Java NIO 日志(即 journal-type 设为 NIO),则默认值为 journal-buffer-timeout 参数。

在前面的示例中,当发送到地址 my.paged.address 的消息超过内存中超过 104857600 字节时,代理开始分页。

注意

如果您在 address-setting 元素中指定 max-size-bytes,则该值将应用到 每个 匹配的地址。指定这个值 并不意味着 所有匹配地址 的总大小 限制为 max-size-bytes 的值。

7.1.3. 配置全局分页大小

有时,每个地址 配置内存限制并不实际,例如,当代理管理有很多具有不同使用模式的地址时。在这些情况下,您可以指定全局内存限制。全局 限制是 代理可用于所有地址的内存量。当达到此内存限制时,代理将为与新传入消息关联的地址执行为 address-full-policy 指定的策略。

以下流程演示了如何配置全局分页大小。

先决条件

流程

  1. 停止代理。

    1. 在 Linux 中:

      <broker_instance_dir>/bin/artemis stop
    2. 在 Windows 中:

      <broker_instance_dir>\bin\artemis-service.exe stop
  2. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  3. core 元素中添加 global-max-size 元素并指定一个值。例如:

    <configuration>
      <core>
        ...
        <global-max-size>1GB</global-max-size>
        ...
      </core>
    </configuration>
    global-max-size

    代理可用于所有地址的内存量,以字节为单位。当达到这个限制时,对于与传入消息关联的地址,代理执行指定为 address-full-policy 的值的策略。global-max-size 默认值为托管代理的 Java 虚拟机(JVM)可用的最大内存的一半。

    global-max-size 的值以字节为单位,但也支持字节表示法(如 "K", "Mb", "GB")

    在前面的示例中,代理配置为在处理消息时使用最多 1GB 可用内存。

  4. 启动代理。

    1. 在 Linux 中:

      <broker_instance_dir>/bin/artemis run
    2. 在 Windows 中:

      <broker_instance_dir>\bin\artemis-service.exe start

7.1.4. 在分页过程中限制磁盘用量

您可以限制代理可在阻止传入信息之前使用的物理磁盘空间量,而不是分页它们。

以下流程演示了如何在分页过程中为磁盘用量设置限制。

流程

  1. 停止代理。

    1. 在 Linux 中:

      <broker_instance_dir>/bin/artemis stop
    2. 在 Windows 中:

      <broker_instance_dir>\bin\artemis-service.exe stop
  2. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  3. core 元素中,添加 max-disk-usage 配置元素并指定一个值。例如:

    <configuration>
      <core>
        ...
        <max-disk-usage>50</max-disk-usage>
        ...
      </core>
    </configuration>
    max-disk-usage

    代理在分页消息时可以使用的可用磁盘空间的最大百分比。当达到这个限制时,代理会阻断传入的信息,而不是分页它们。默认值为 90

    在上例中,当分页消息时,代理限制为使用 fifty 磁盘空间。

  4. 启动代理。

    1. 在 Linux 中:

      <broker_instance_dir>/bin/artemis run
    2. 在 Windows 中:

      <broker_instance_dir>\bin\artemis-service.exe start

7.2. 配置消息丢弃

第 7.1.2 节 “为分页配置地址” 显示如何为分页配置地址。作为该流程的一部分,您要将 address-full-policy 的值设置为 PAGE

当地址达到指定的最大值时,要丢弃 消息(而不是分页),将 address-full-policy 的值设置为以下之一:

DROP
当达到给定地址的最大大小时,代理会静默丢弃任何进一步的信息。
FAIL
当达到给定地址的最大大小时,代理会丢弃任何进一步的消息和问题例外。

7.3. 配置消息阻塞

以下流程演示了如何在给定地址达到您指定的最大大小限制时配置消息块。

注意

只能为 Core、OpenWire 和 AMQP 协议配置消息阻塞。

7.3.1. 阻塞内核和 OpenWire producers

以下流程演示了如何在给定地址达到您指定的最大大小限制时为 Core 和 OpenWire 消息制作器配置消息块。

先决条件

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 对于您为匹配地址 或一组 地址配置的 address-setting 元素,请添加配置元素以定义消息块行为。例如:

    <address-settings>
        <address-setting match="my.blocking.address">
            ...
            <max-size-bytes>300000</max-size-bytes>
            <address-full-policy>BLOCK</address-full-policy>
            ...
        </address-setting>
    </address-settings>
    max-size-bytes

    在代理执行为 address-full-policy 指定的策略前,地址允许的内存的最大大小(以字节为单位)。您指定的值还支持字节表示法,如"K"、"MB"和"GB"。

    注意

    如果您在 address-setting 元素中指定 max-size-bytes,则该值将应用到 每个 匹配的地址。指定这个值 并不意味着 所有匹配地址 的总大小 限制为 max-size-bytes 的值。

    address-full-policy
    然后,达到地址的最大大小时代理要执行的操作。

    在前面的示例中,当发送到内存中的地址 my.blocking.address 的消息超过 300000 字节时,代理开始阻止来自 Core 或 OpenWire 消息的进一步消息。

7.3.2. 阻塞 AMQP 生产者

Core 和 OpenWire 等协议使用窗口大小流控制系统。在此系统中,贡献度代表字节数,并且被分配给生产者。如果制作者想要发送消息,则生产者必须等到其有足够贡献度来获得消息的大小。

相反,AMQP 流控制度不代表字节数。相反,AMQP 学位代表允许发送者的消息数量,而不考虑消息大小。因此,在某些情况下 AMQP 生产者可能会显著超过地址的 max-size-bytes 值。

因此,要阻止 AMQP 制作者,您必须使用不同的配置元素 max-size-bytes-reject-threshold。对于匹配的地址或一组地址,此元素指定内存中所有 AMQP 消息的最大值。当内存中的所有消息的总大小达到指定的限制时,代理会阻止 AMQP 生产者发送更多消息。

以下步骤演示了如何为 AMQP 消息制作者配置消息块。

先决条件

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 对于您为匹配地址 或一组 地址配置的 address-setting 元素,请指定内存中所有 AMQP 消息的最大值。例如:

    <address-settings>
        <address-setting match="my.amqp.blocking.address">
            ...
            <max-size-bytes-reject-threshold>300000</max-size-bytes-reject-threshold>
            ...
        </address-setting>
    </address-settings>
    max-size-bytes-reject-threshold

    在代理阻止进一步的 AMQP 消息前允许的地址允许的内存的最大大小,以字节为单位。您指定的值还支持字节表示法,如"K"、"MB"和"GB"。默认情况下,max-size-bytes-reject-threshold 设置为 -1,这意味着没有最大大小。

    注意

    如果您在 address-setting 元素中指定 max-size-bytes-reject-threshold,则该值将应用到 每个 匹配的地址。指定这个值 并不意味着 所有匹配地址 的总大小 限制为 max-size-bytes-reject-threshold 的值。

在前面的示例中,当发送到地址 my.amqp.blocking.address 的消息超过 300000 字节时,代理开始阻止来自 AMQP producer 的进一步消息。

7.4. 了解多播地址的内存用量

当消息路由到绑定了多播队列的地址时,在内存中只有一个消息副本。每个队列仅具有对邮件的引用。因此,仅在引用消息 的所有 队列后发布相关的内存。

在这种情形中,如果您有一个较慢的使用者,整个地址可能会给性能造成负面影响。

例如,考虑这种情况:

  • 地址具有十个队列,这些队列使用多播路由类型。
  • 由于使用者缓慢,其中一个队列不会向其消息发送。其他 9 个队列继续传递消息并为空。
  • 消息继续到达地址。缓慢的消费者的队列会继续积累对消息的引用,从而导致代理在内存中保存消息。
  • 当达到最大地址大小时,代理将启动到页面信息。

在这种情况下,因为一个较慢的消费者 强制使用来自页面系统的消息,这需要其他 IO。

其他资源

  • 要了解如何配置流控制,以规范代理和制作者与消费者之间的数据流,请参阅 AMQ Core Protocol JMS 文档中的 流控制

第 8 章 处理大型消息

客户端可能会发送超过代理内部缓冲大小的大量信息,从而导致意外错误。要防止这种情况,您可以将代理配置为在消息大于指定最小值时存储信息。以这种方式处理大型消息意味着代理不会在内存中保存消息。相反,您会在磁盘或者代理存储大量消息文件的数据库表中指定一个目录。

当代理将消息存储为大消息时,队列会保留对大型消息目录或数据库表中的文件的引用。

大型消息处理可用于 Core Protocol、AMQP、OpenWire 和 STOMP 协议。

对于核心协议和 OpenWire 协议,客户端在其连接配置中指定最小大量消息大小。对于 AMQP 和 STOMP 协议,您可以在代理配置中为每个协议定义的接受器指定最小消息大小。

注意

建议您 不要将 不同的协议用于生成和使用大型消息。要做到这一点,代理可能需要执行消息的一些转换。例如,假设您想使用 AMQP 协议发送消息并使用 OpenWire 进行接收。在这种情况下,代理必须首先读取大型消息的整个正文,并将其转换为使用 Core 协议。然后,代理必须执行另一个转换,这一次是 OpenWire 协议。比如这些信息转换,比如在代理中造成大量处理开销。

您在上述任何协议中指定的最小消息大小会受系统资源的影响,如可用的磁盘空间量,以及消息的大小。建议您使用多个值运行性能测试来确定适当的大小。

本节中的步骤演示了如何:

  • 配置代理以存储大型消息
  • 为大型消息处理配置 AMQP 和 STOMP 协议的接收器

本节还链接到配置 AMQ Core Protocol 和 AMQ OpenWire JMS 客户端以用于大量消息的其他资源。

8.1. 为大型消息处理配置代理

以下流程演示了如何指定磁盘中的目录或代理存储大型消息文件的数据库表。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 指定代理在哪里存储大型消息文件。

    1. 如果您在磁盘上存储大量消息,请在 core 元素中添加 large-messages-directory 参数并指定文件系统位置。例如:

      <configuration>
        <core>
          ...
          <large-messages-directory>/path/to/my-large-messages-directory</large-messages-directory>
          ...
        </core>
      </configuration>
      注意

      如果您没有显式为 large-messages-directory 指定值,代理使用默认值 < broker_instance_dir> /data/largemessages

    2. 如果您在数据库表中存储大型消息,请将 large-message-table 参数添加到 database-store 元素并指定一个值。例如:

      <store>
        <database-store>
          ...
          <large-message-table>MY_TABLE</large-message-table>
          ...
        </database-store>
      </store>
      注意

      如果您没有为 large-message-table 明确指定值,代理将使用默认值 LARGE_MESSAGE_TABLE

其他资源

8.2. 为大型消息处理配置 AMQP 接受器

以下流程演示了如何配置 AMQP 接受器来处理大于指定大小作为较大消息的 AMQP 消息。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。

    代理配置文件中的默认 AMQP 接受器类似如下:

    <acceptors>
        ...
        <acceptor name="amqp">tcp://0.0.0.0:5672?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=AMQP;useEpoll=true;amqpCredits=1000;amqpLowCredits=300</acceptor>
        ...
    </acceptors>
  2. 在默认的 AMQP acceptor(或者您配置的 AMQP 接受器)中,添加 amqpMinLargeMessageSize 属性并指定值。例如:

    <acceptors>
        ...
        <acceptor name="amqp">tcp://0.0.0.0:5672?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=AMQP;useEpoll=true;amqpCredits=1000;amqpLowCredits=300;amqpMinLargeMessageSize=204800</acceptor>
        ...
    </acceptors>

    在前面的示例中,代理配置为接受端口 5672 上的 AMQP 信息。根据 amqpMinLargeMessageSize 的值,如果 acceptor 收到一个大于 204800 字节的 AMQP 消息(即 200 KB),代理会将消息存储为大消息。如果您没有为此属性明确指定值,代理将使用默认值 102400(即 100 KB)。

注意
  • 如果将 amqpMinLargeMessageSize 设为 -1,则会禁用 AMQP 消息的大型消息处理。
  • 如果代理收到一个持久性 AMQP 消息,它没有超过 amqpMinLargeMessageSize 的值,但超出消息传递日志缓冲区的大小(使用 journal-buffer-size 配置参数指定),代理会将消息转换为大型核心协议消息,然后再将其存储在日志中。

8.3. 为大型消息处理配置 STOMP 接受器

以下流程演示了如何配置 STOMP 接受器来处理大于指定大小作为较大消息的 STOMP 消息。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。

    代理配置文件中的默认 AMQP 接受器类似如下:

    <acceptors>
        ...
        <acceptor name="stomp">tcp://0.0.0.0:61613?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=STOMP;useEpoll=true</acceptor>
        ...
    </acceptors>
  2. 在默认的 STOMP acceptor(或者您配置的另一个 STOMP 接受器)中,添加 stompMinLargeMessageSize 属性并指定值。例如:

    <acceptors>
        ...
        <acceptor name="stomp">tcp://0.0.0.0:61613?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=STOMP;useEpoll=true;stompMinLargeMessageSize=204800</acceptor>
        ...
    </acceptors>

在上例中,代理被配置为接受端口 61613 上的 STOMP 信息。根据 stompMinLargeMessageSize 的值,如果接受者收到大于等于 204800 字节的 STOMP 消息(即 200 KB),则代理将消息存储为大消息。如果您没有为此属性明确指定值,代理将使用默认值 102400(即 100 KB)。

注意

要为 STOMP 消费者发送大量消息,代理会在将其发送到客户端前自动将消息从大型消息转换为正常消息。如果压缩大量信息,代理会在将其发送到 STOMP 客户端前将其解压缩。

8.4. 大型消息和 Java 客户端

编写使用大型消息的客户端的 Java 开发人员有两种选项。

其中一种选项是使用 InputStreamOutputStream 的实例。例如,可以使用 FileInputStream 发送来自物理磁盘上的大型文件的消息。然后,接收器可以使用 文件OutputStream 将消息流传输到其本地文件系统中的位置。

另一选择是直接向 JMS BytesMessageStreamMessage 传输。例如:

BytesMessage rm = (BytesMessage)cons.receive(10000);
byte data[] = new byte[1024];
for (int i = 0; i < rm.getBodyLength(); i += 1024)
{
   int numberOfBytes = rm.readBytes(data);
   // Do whatever you want with the data
}

其他资源

第 9 章 检测已弃用连接

有时,客户端意外停止,且不会有机会清除其资源。如果出现这种情况,它可以使资源处于故障状态,并导致代理内存不足或其他系统资源。代理检测到客户端的连接在垃圾回收时没有正确关闭。然后,连接关闭,类似于以下内容的消息将写入到日志中。日志捕获客户端会话实例化的确切代码行。这可让您识别错误并进行更正。

[Finalizer] 20:14:43,244 WARNING [org.apache.activemq.artemis.core.client.impl.DelegatingSession]  I'm closing a JMS Conection you left open. Please make sure you close all connections explicitly before let
ting them go out of scope!
[Finalizer] 20:14:43,244 WARNING [org.apache.activemq.artemis.core.client.impl.DelegatingSession]  The session you didn't close was created here:
java.lang.Exception
   at org.apache.activemq.artemis.core.client.impl.DelegatingSession.<init>(DelegatingSession.java:83)
   at org.acme.yourproject.YourClass (YourClass.java:666) 1
1
连接实例化的客户端代码中的行。

9.1. 连接时间-To-Live

因为客户端和服务器间的网络连接会失败,然后返回在线,因此允许客户端重新连接,AMQ Broker 会等待清理不活跃的服务器端资源。这个等待时间被称为生存时间(TTL)。基于网络的连接的默认 TTL 为 60000 毫秒(1 分钟)。在 VM 连接上的默认 TTL 是 -1,这意味着代理永远不会在代理方中造成连接。

在代理中配置 Time-To-Live

如果您不希望客户端指定自己的连接 TTL,可以在代理一侧设置全局值。这可以通过在代理配置中指定 connection-ttl-override 元素来实现。

检查 TTL 冲突连接的逻辑定期在代理上运行,如 connection-ttl-check-interval 元素所决定。

流程

  • 编辑 < broker_instance_dir> /etc/broker.xml,方法是添加 connection-ttl-override 配置元素并为生存提供一个值,如下例所示。

    <configuration>
     <core>
      ...
      <connection-ttl-override>30000</connection-ttl-override> 1
      <connection-ttl-check-interval>1000</connection-ttl-check-interval> 2
      ...
     </core>
    </configuration>
    1
    所有连接的全局 TTL 被设置为 30000 毫秒。默认值为 -1,它允许客户端设置自己的 TTL。
    2
    死连接之间的间隔设置为 1000 毫秒。默认情况下,检查会每 2000 毫秒进行一次。

9.2. 禁用同步连接执行

代理一边接收的大多数数据包都是在远程线程 上执行的。这些数据包代表短暂运行的操作,并且始终在远程线程上执行,以提高性能。但是,有些数据包类型使用线程池执行,而不是使用远程线程,这会增加较少的网络延迟。

使用线程池的数据包类型在下列 Java 类中实施。类都位于软件包 org.apache.actiinvemq.artemis.core.impl.wireformat

  • RollbackMessage
  • SessionCloseMessage
  • SessionCommitMessage
  • SessionXACommitMessage
  • SessionXAPrepareMessage
  • SessionXARollbackMessage

流程

  • 要禁用异步连接执行,将 async-connection-execution-enabled 配置元素添加到 & lt;broker_instance_dir> /etc/broker.xml,并将其设置为 false,如下例所示。默认值为 true

    <configuration>
     <core>
      ...
      <async-connection-execution-enabled>false</async-connection-execution-enabled>
      ...
     </core>
    </configuration>

其他资源

第 10 章 检测重复的信息

您可以将代理配置为自动检测和过滤重复的消息。这意味着您不必实现自己的重复检测逻辑。

如果没有重复的检测,在意外连接失败时,客户端无法确定它发送到代理的消息。在这种情况下,客户端可能会假定代理没有收到消息,并重新发送它。这会生成重复的消息。

例如,假设客户端向代理发送一条消息。如果在代理接收和处理消息 代理失败,则消息永远不会到达其地址。因为失败,客户端不会从代理收到响应。如果在代理接收和处理 消息后 代理失败代理或连接,则会正确路由该消息,但客户端仍然不会再收到响应。

另外,在这种情况下,使用事务来确定是否成功。如果在处理事务提交时代理或连接失败,客户端仍无法确定它能否成功发送该消息。

在这些情况下,为了修正假定的失败,客户端会重新发送最新消息。结果可能是对您的系统有负面影响的重复消息。例如,如果您在订购系统中使用代理,则重复的消息可能意味着对订购的处理两次。

以下流程演示了如何配置重复的消息检测,以防出现这些类型的情况。

10.1. 配置重复的 ID 缓存

要启用代理来检测重复的消息,制作者必须在发送每个消息时为消息属性 _AMQ_DUPL_ID 提供唯一值。代理维护 _AMQ_DUPL_ID 属性的接收值的缓存。当代理在地址上收到新消息时,它会检查该地址的缓存,以确保之前没有处理与此属性相同的值相同的消息。

每个地址都有自己的缓存。每个缓存的大小都是圆形和固定。这意味着新条目会替换最旧的缓存空间需求。

以下流程演示了如何全局配置代理中每个地址使用的 ID 缓存。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. core 元素中,添加 id-cache-sizepersist-id-cache 属性并指定值。例如:

    <configuration>
      <core>
        ...
        <id-cache-size>5000</id-cache-size>
        <persist-id-cache>false</persist-id-cache>
      </core>
    </configuration>
    id-cache-size

    ID 缓存的最大大小,指定为缓存中的独立条目数量。默认值为 20,000 个条目。在本例中,缓存大小设置为 5,000 条目。

    注意

    当达到缓存的最大大小时,代理可能会开始处理重复的信息。例如,假设您将缓存大小设置为 3000。如果前面的消息在 arrival 具有相同 _AMQ_DUPL_ID 值相同的新消息前到达了 3,000 多个 消息,则代理无法检测到重复的。这会导致代理处理这两个信息。

    persist-id-cache
    当此属性的值设置为 true 时,代理会在收到该属性时将 ID 持久化到磁盘。默认值为 true。在上例中,您可以通过将值设为 false 来禁用持久性。

其他资源

  • 要了解如何使用 AMQ Core Protocol JMS 客户端设置重复的 ID 消息属性,请参阅 AMQ Core Protocol JMS 客户端文档中的 使用重复消息检测

10.2. 为集群状态配置重复的检测

您可以配置集群连接,为跨集群的每个消息插入重复的 ID 标头。

先决条件

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 在给定集群连接的 core 元素内,添加 use-duplicate-detection 属性并指定值。例如:

    <configuration>
      <core>
        ...
        <cluster-connections>
           <cluster-connection name="my-cluster">
             <use-duplicate-detection>true</use-duplicate-detection>
             ...
           </cluster-connection>
             ...
        </cluster-connections>
      </core>
    </configuration>
    use-duplicate-detection
    当此属性的值设置为 true 时,集群连接会为它处理的每个消息插入重复的 ID 标头。

第 11 章 截屏信息

使用 AMQ Broker,您可以截获数据包进入或退出代理,以便您审核数据包或过滤信息。拦截器可能会更改其截获的数据包,使其功能强大,但也存在危险性。

您可以开发拦截器来满足您的业务需求。拦截器是特定于协议的,必须实现适当的接口。

拦截器必须实现 intercept() 方法,该方法返回布尔值。如果值为 true,则消息数据包将继续返回。如果为 false,则进程中止,不会调用其他拦截器,且不会进一步处理消息数据包。

11.1. 创建拦截器

您可以创建自己的传入和传出拦截器。所有拦截器都是特定的协议,为分别进入或退出服务器的任何数据包调用。这可让您创建拦截器来满足商业要求,如审核数据包。拦截器可能会更改其被截获的数据包。这使得它们既强大以及潜在的危险性,因此请务必谨慎使用。

拦截器及其依赖项必须放在代理的 Java 类路径中。您可以使用 &lt ;broker_instance_dir> /lib 目录,因为它是 classpath 的一部分。

流程

以下示例演示了如何创建检查传递给它的每个数据包的拦截器。请注意,示例为每个协议实施特定的接口。

  • 实施适当的接口并覆盖其 intercept() 方法。

    • 如果您使用 AMQP 协议,请实施 org.apache.activemq.artemis.protocol.amqp.broker.AmqpInterceptor 接口。

      package com.example;
      
      import org.apache.activemq.artemis.protocol.amqp.broker.AMQPMessage;
      import org.apache.activemq.artemis.protocol.amqp.broker.AmqpInterceptor;
      import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
      
      public class MyInterceptor implements AmqpInterceptor
      {
        private final int ACCEPTABLE_SIZE = 1024;
      
        @Override
        public boolean intercept(final AMQPMessage message, RemotingConnection connection)
        {
          int size = message.getEncodeSize();
          if (size <= ACCEPTABLE_SIZE) {
            System.out.println("This AMQPMessage has an acceptable size.");
            return true;
          }
          return false;
        }
      }
    • 如果您使用的是内核协议,您的拦截器必须实施 org.apache.artemis.activemq.api.core.Interceptor 接口。

      package com.example;
      
      import org.apache.artemis.activemq.api.core.Interceptor;
      import org.apache.activemq.artemis.core.protocol.core.Packet;
      import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
      
      public class MyInterceptor implements Interceptor
      {
        private final int ACCEPTABLE_SIZE = 1024;
      
        @Override
        boolean intercept(Packet packet, RemotingConnection connection)
        throws ActiveMQException
        {
          int size = packet.getPacketSize();
          if (size <= ACCEPTABLE_SIZE) {
            System.out.println("This Packet has an acceptable size.");
            return true;
          }
          return false;
        }
      }
    • 如果您使用 IFL 协议,实施 org.apache.activemq.artemis.core.protocol.mqtt.awxInterceptor 接口。

      package com.example;
      
      import org.apache.activemq.artemis.core.protocol.mqtt.MQTTInterceptor;
      import io.netty.handler.codec.mqtt.MqttMessage;
      import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
      
      public class MyInterceptor implements Interceptor
      {
        private final int ACCEPTABLE_SIZE = 1024;
      
        @Override
        boolean intercept(MqttMessage mqttMessage, RemotingConnection connection)
        throws ActiveMQException
        {
          byte[] msg = (mqttMessage.toString()).getBytes();
          int size = msg.length;
          if (size <= ACCEPTABLE_SIZE) {
            System.out.println("This MqttMessage has an acceptable size.");
            return true;
          }
          return false;
        }
      }
    • 如果您使用 STOMP 协议,请实施 org.apache.activemq.artemis.core.protocol.stomp.StompeInterceptor 接口。

      package com.example;
      
      import org.apache.activemq.artemis.core.protocol.stomp.StompFrameInterceptor;
      import org.apache.activemq.artemis.core.protocol.stomp.StompFrame;
      import org.apache.activemq.artemis.spi.core.protocol.RemotingConnection;
      
      public class MyInterceptor implements Interceptor
      {
        private final int ACCEPTABLE_SIZE = 1024;
      
        @Override
        boolean intercept(StompFrame stompFrame, RemotingConnection connection)
        throws ActiveMQException
        {
          int size = stompFrame.getEncodedSize();
          if (size <= ACCEPTABLE_SIZE) {
            System.out.println("This StompFrame has an acceptable size.");
            return true;
          }
          return false;
        }
      }

11.2. 将代理配置为使用拦截器

创建拦截器后,您必须配置代理才能使用它。

先决条件

您必须创建一个拦截器类,并将其(及其依赖项)添加到代理的 Java 类路径中,然后才能将其配置为代理使用。您可以使用 &lt ;broker_instance_dir> /lib 目录,因为它是 classpath 的一部分。

流程

  • 通过将配置添加到 <broker _instance_dir&gt; /etc/broker.xml,将代理配置为使用拦截器

    • 如果您的拦截器用于传入信息,请将其 class-name 添加到 remoting-incoming-interceptors 列表中。

      <configuration>
        <core>
          ...
          <remoting-incoming-interceptors>
             <class-name>org.example.MyIncomingInterceptor</class-name>
          </remoting-incoming-interceptors>
          ...
        </core>
      </configuration>
    • 如果您的拦截器用于传出消息,请将其 class-name 添加到 remoting-outgoing-interceptors 列表中。

      <configuration>
        <core>
          ...
          <remoting-outgoing-interceptors>
             <class-name>org.example.MyOutgoingInterceptor</class-name>
          </remoting-outgoing-interceptors>
        </core>
      </configuration>

其他资源

  • 要在 AMQ Core Protocol JMS 客户端中配置拦截器,请参阅在 AMQ Core Protocol JMS 文档中 使用消息拦截器

第 12 章 分离消息和分割消息流

在 AMQ Broker 中,您可以配置名为 par rts 的对象,以便您以透明的方式将信息从一个地址转移到另一个地址,而无需更改任何客户端应用程序逻辑。您还可以将消息 的副本 转发到指定的转发地址,从而有效地分割消息流。

12.1. 消息划分方式

通过导航信息,您可以透明地将消息重新定向到其他地址,而不更改任何客户端应用程序逻辑。把一个代理服务器分离为消息的路由表类型。

分化器可以 独占 的,即消息被转移到指定的转发地址,而不会进入其原始地址。

条带化也可以是 非排除的,这意味着,一条信息将继续进入其原始地址,而代理会将消息的副本发送到指定的转发地址。因此,您可以为拆分消息流使用非排除的导航。例如,如果您想要单独监控一个订购队列的每个顺序,您可以分割消息流。

当地址同时配置了独占的分项和非排除条时,代理首先会处理独占的差异。如果已经通过独占的分离出了特定的消息,则代理不会处理该消息的任何非排除差别。在这种情况下,消息永远不会指向原始地址。

当代理分离一个消息时,代理会分配新的消息 ID,并将消息地址设置为新的转发地址。您可以通过 _AMQ_ORIG_ADDRESS (字符串类型)和 _AMQ_ORIG_MESSAGE_ID (长类型)消息属性来检索原始消息 ID 和地址值。如果您使用 Core API,请使用 Message.HDR_ORIGINAL_ADDRESSMessage.HDR_ORIG_MESSAGE_ID 属性。

注意

您只能将消息重新定向到同一代理服务器上的地址。如果要分入不同服务器上的地址,常用的解决方案是首先将消息重新定向至本地存储和转发队列。然后,设置从该队列使用的网桥,并将消息转发到不同代理上的地址。通过将分制与网桥相结合,您可以在地理分布代理服务器之间创建分布式路由连接网络。这样,您可以创建一个全局消息传递网格。

12.2. 配置消息片段

要在代理实例中配置,请在 broker.xml 配置文件的 核心元素 中添加 divert 元素。

<core>
...
   <divert name= >
        <address> </address>
        <forwarding-address> </forwarding-address>
        <filter string= >
        <routing-type> </routing-type>
        <exclusive> </exclusive>
   </divert>
...
</core>
divert
划分的命名实例.您可以向 broker.xml 配置文件添加多个 divert 元素,只要每个竞争者都有唯一的名称。
address
从中分离 信息的地址
forwarding-address
信息转发的地址
filter
可选的消息过滤器。如果您配置过滤器,则只会显示与过滤器字符串匹配的消息。如果您没有指定过滤器,则整个消息都将被视为匹配。
routing-type

正在推断的消息的路由类型。您可以将竞争配置为:

  • 将任何 广播多播路由 类型应用到消息
  • 条带 (即,删除)现有路由类型
  • 传递 (即保留)现有路由类型

当消息已设置其路由类型时,路由类型的控制很有用,但您想将消息重新定向到使用不同的路由类型的地址。例如,代理无法将 anycast 路由类型的消息路由到一个使用 multicast 的队列,除非您将 divert 的 routing-type 参数设置为 MULTICAST。导航器的 routing-type 参数有效值为 ANYCASTMULTICASTPASSSTRIP。默认值为 STRIP

exclusive
指定parrt 是否排斥(将属性设置为 true)还是非独占(将属性设置为 false)。

以下小节显示了独占和非排除分制的配置示例。

12.2.1. 独占竞争示例

下面是一个排斥的示例配置。独占的分点将最初配置的地址中的所有匹配消息重定向到新地址。匹配的消息不会路由到原始地址。

<divert name="prices-divert">
   <address>priceUpdates</address>
   <forwarding-address>priceForwarding</forwarding-address>
   <filter string="office='New York'"/>
   <exclusive>true</exclusive>
</divert>

在前面的示例中,您定义了一个名为 price-divert 的 divert,它将发送到 priceUpdates 地址的任何消息转到另外一个本地地址 priceForwarding。您还指定了消息过滤器字符串。只有消息属性 office 和值 New York 的消息才会被推断。所有其他消息都路由到其原始地址。最后,您指定了分路是独占的。

12.2.2. Non-exclusive divert 示例

下面是一个非区别的示例配置。在非专用的竞争中,信息将继续进入其原始地址,而代理也会将消息的副本发送到指定的转发地址。因此,非破坏性的划分方式是分割消息流的方法。

<divert name="order-divert">
   <address>orders</address>
   <forwarding-address>spyTopic</forwarding-address>
   <exclusive>false</exclusive>
</divert>

在前面的示例中,您可以定义名为 order-divert 的分值,该片段获取发送到地址 订购 的每个消息的副本并将其发送到名为 spyTopic 的本地地址。您还指定了不明确推销。

其他资源

如需详细示例,它使用 exclusive 和 non-clusive 分离和网桥将消息转发到另一个代理,请参阅 Divert Example (外部)。

第 13 章 过滤信息

AMQ Broker 根据 SQL 92 表达式语法的子集提供强大的过滤器语言。过滤器语言使用与 JMS 选择器相同的语法,但预定义的标识符不同。下表列出了应用到 AMQ Broker 消息的标识符。

标识符属性

AMQPriority

消息的优先级。消息优先级是带有从 09 的有效值的整数。0 是最低的优先级,9 是最高。

AMQExpiration

消息的过期时间。该值是一个长整数。

AMQDurable

消息是否持久。值是字符串。有效值为 DURABLENON_DURABLE

AMQTimestamp

创建消息的时间戳。该值是一个长整数。

AMQSize

消息的 encodeSize 属性的值。encodeSize 的值是空格(以字节为单位),消息在日志中取。因为代理使用双字节字符集对消息进行编码,因此消息的实际大小是 encodeSize 的值的一半。

核心过滤器表达式中使用的任何其他标识符都假定是消息的属性。有关 JMS 消息的选择器语法的文档,请参阅 Java EE API

13.1. 将队列配置为使用过滤器

您可以在 < broker_instance_dir> /etc/broker.xml 中配置的队列中添加过滤器。仅与过滤器表达式匹配的消息即可进入队列。

流程

  • 过滤器 元素添加到所需的 队列,并包含您要应用的过滤器,作为元素的值。在以下示例中,过滤器 NEWS=' Technology' 已添加到队列 技术Queue 中。

    <configuration>
      <core>
        ...
        <addresses>
            <address name="myQueue">
               <anycast>
                  <queue name="myQueue">
                    <filter string="NEWS='technology'"/>
                  </queue>
               </anycast>
            </address>
         </addresses>
       </core>
    </configuration>

13.2. 过滤 JMS 消息属性

JMS 规格指出在选择器中使用的 String 属性不得转换为数字类型。例如,如果消息将 age 属性设置为 String 值 21,则选择器 年龄 > 18 不得与它匹配。这个限制会限制 STOMP 客户端,因为它们只能使用 String 属性发送信息。

配置过滤器将字符串转换为数字

要将字符串属性转换为数字类型,请将前缀 convert_string_expressions: 添加到 过滤器 的值。

流程

  • 编辑 <broker_instance_dir> /etc/broker.xml,将前缀 convert_string_expressions: 应用到所需的 过滤器。以下示例编辑 filter 值从 age > 18 to convert_string_expressions:age > 18

    <configuration>
      <core>
        ...
        <addresses>
            <address name="myQueue">
               <anycast>
                  <queue name="myQueue">
                    <filter string="convert_string_expressions='age > 18'"/>
                  </queue>
               </anycast>
            </address>
         </addresses>
       </core>
    </configuration>

13.3. 根据注释上的属性过滤 AMQP 消息

在代理移动过期或未发送的 AMQP 消息前,到您配置的过期或死信队列,代理会将注解和属性应用到消息。客户端可以根据属性或注解创建过滤器,以从到期或死信队列中选择使用的特定消息。

注意

代理适用的属性是 内部 属性,这些属性不会暴露给客户端供常规使用,但 可由 过滤器中的客户端指定。

以下是基于消息属性和注解的过滤器示例。根据属性过滤是推荐的方法,因为这种方法需要较少的代理处理。

基于消息属性进行过滤

ConnectionFactory factory = new JmsConnectionFactory("amqp://localhost:5672");
Connection connection = factory.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
connection.start();
javax.jms.Queue queue = session.createQueue("my_DLQ");
MessageConsumer consumer = session.createConsumer(queue, "_AMQ_ORIG_ADDRESS='original_address_name'");
Message message = consumer.receive();

基于消息注解进行过滤

ConnectionFactory factory = new JmsConnectionFactory("amqp://localhost:5672");
Connection connection = factory.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
connection.start();
javax.jms.Queue queue = session.createQueue("my_DLQ");
MessageConsumer consumer = session.createConsumer(queue, "\"m.x-opt-ORIG-ADDRESS\"='original_address_name'");
Message message = consumer.receive();

注意

在使用基于注解的 AMQP 消息时,客户端必须包含 m. 前缀到消息注解,如上例中所示。

其他资源

13.4. 过滤 XML 消息

AMQ Broker 提供了过滤文本消息的方式,其包含使用 XPath 的 XML 正文。XPath(XML Path Language)是用于从 XML 文档选择节点的查询语言。

注意

仅支持基于文本的信息。不支持过滤大型消息。

要过滤基于文本的消息,您需要创建一个 XPATH '<xpath-expression> 形式的 Message Selector。

Message Body 的示例

<root>
    <a key='first' num='1'/>
    <b key='second' num='2'>b</b>
</root>

基于 XPath 查询进行过滤

PATH 'root/a'

警告

因为 XPath 适用于邮件的正文,因此需要解析 XML,所以过滤速度明显比普通过滤器要慢。

XPath 过滤器支持使用下列协议的生产者和使用者之间的差别:

  • OpenWire JMS
  • 内核(和核心 JMS)
  • STOMP
  • AMQP
配置 XML 解析器

默认情况下,代理使用的 XML 解析程序是 JDK 使用的平台默认 DocumentBuilderFactory 实例。

用于 XPath 默认配置的 XML 解析程序包括以下设置:

但是,为了处理任何特定于实施的问题,可以在 artemis.profile 配置文件中配置 System 属性来自定义功能。

org.apache.activemq.documentBuilderFactory.feature:prefix

功能配置示例

-Dorg.apache.activemq.documentBuilderFactory.feature:http://xml.org/sax/features/external-general-entities=true

第 14 章 设置代理集群

集群由多个已分组在一起的代理实例组成。代理集群通过在多个代理间分布消息处理负载来提高性能。另外,代理集群可以通过高可用性来最小化停机时间。

您可以在许多不同的集群拓扑中连接代理。在集群中,每个活跃代理都管理自己的消息并处理自己的连接。

您还可以在集群中平衡客户端连接并重新分发消息以避免代理不足。

14.1. 了解代理集群

在创建代理集群前,您应该了解一些重要的集群概念。

14.1.1. 代理集群如何平衡消息负载

当代理连接到形成集群时,AMQ Broker 会在代理之间自动平衡消息负载。这样可确保集群可以保持高消息吞吐量。

考虑四个代理的对称集群。每个代理都配置了名为 OrderQueue 的队列。OrderProducer 客户端连接到 Broker1,并将消息发送到 OrderQueueBroker1 以轮循方式将消息转发到其他代理。连接到每个代理的 OrderConsumer 客户端使用消息。

图 14.1. 消息负载均衡

信息在集群中的代理之间平衡负载

如果没有消息负载平衡,发送到 Broker1 的消息将保留在 Broker1 中,只有 OrderConsumer1 能够消耗它们。

默认情况下,AMQ Broker 会自动负载平衡消息,将第一个消息组分发到第一个代理,并将第二条消息组分发到第二个代理。这个代理启动的顺序决定了哪个代理是第一的代理,第二个代理。

您可以配置:

  • 将消息负载平衡到具有匹配队列的代理的集群。
  • 集群将消息负载平衡到具有活跃消费者匹配队列的代理。
  • 集群无法负载平衡,但要执行从没有任何消费者消费者的队列上重新分发的消息。
  • 从没有消费者消费者的队列自动重新分发消息的地址。

其他资源

14.1.2. 代理集群如何提高可靠性

代理集群使高可用性和故障转移成为可能,使其比独立代理更可靠。通过配置高可用性,您可以确保客户端应用程序可以继续发送和接收消息,即使代理遇到失败事件。

使用高可用性功能时,集群中的代理被分组到 live-backup 组。live-backup 组包含提供客户端请求的实时代理,以及一个或多个备份代理(如果是被动)替换实时代理(如果失败)。如果发生故障,备份代理会替代其 live-backup 组中的 live 代理,客户端会重新连接并继续工作。

14.1.3. 集群限制

在集群环境中使用 AMQ 代理时,会有以下限制。

临时队列
在故障切换过程中,如果客户端有使用临时队列的使用者,则这些队列会自动重新创建。重新创建队列名称与原始队列名称不匹配,这会导致消息重新分发失败,并可使消息显示在现有临时队列中。红帽建议您避免在集群中使用临时队列。例如,使用请求/回复模式的应用程序应该将固定队列用于 JMSReplyTo 地址。

14.1.4. 了解节点 ID

代理 节点 ID 是全球唯一识别符(GUID),在首次创建和初始化代理实例时以编程方式生成。节点 ID 存储在 server.lock 文件中。节点 ID 用于唯一标识代理实例,无论代理是独立实例还是集群的一部分。实时备份代理对共享相同的节点 ID,因为它们共享相同的日志。

在代理集群中,代理实例(节点)互相连接,并创建网桥和内部 "store-and-forward" 队列。这些内部队列的名称基于其他代理实例的节点 ID。代理实例还监控与其自身匹配的节点 ID 的集群广播。如果代理标识了重复的 ID,则代理会在日志中生成警告消息。

当您使用复制高可用性(HA)策略时,启动并设置了 check-for-live-server 的主 代理会搜索使用其节点 ID 的代理。如果 master 代理使用相同的节点 ID 找到另一个代理,则根据 HA 配置启动或启动故障恢复。

节点 ID 是持久的,这意味着它可在重启代理后保留。但是,如果您删除一个代理实例(包括其日志),则节点 ID 也会被永久删除。

其他资源

14.1.5. 通用代理集群拓扑

您可以将代理连接到形成 对称 集群拓扑。您实现的拓扑取决于您的环境和消息要求。

对称集群

在对称集群中,每个代理都连接到所有其他代理。这意味着每个代理都没有超过一 个退出其它代理。

图 14.2. 对称集群

在四代理对称集群中,每个代理都连接到其他代理

对称集群中的每个代理都知道集群中所有其他代理上存在的所有队列,以及侦听这些队列的用户。因此,与链集群相比,对称集群可以更好地加载平衡和重新分发消息。

对称集群比链集群更容易设置,但在网络限制阻止代理无法直接连接的环境中可能很难使用。

链集群

在链集群中,集群中的每个代理都没有直接连接到集群中的每个代理。相反,代理会组成一个链,且每个链末尾都有一个代理,所有其他代理仅在链中连接前和下一个代理。

图 14.3. 链集群

在四代理链集群中,代理在链中连接

链集群比对称集群更难以设置,但在代理位于独立的网络中且无法直接连接时非常有用。通过使用链集群,中间代理也可以间接连接两个代理,以便即使两个代理没有直接连接,也会让消息在它们之间进行流。

14.1.6. 代理发现方法

Discovery 是集群中的代理机制,其连接详情会相互传播。AMQ Broker 支持动态发现 和静态发现

动态发现

集群中的每个代理都会通过 UDP 多播或 JGroups 广播其连接设置到其他成员。在此方法中,每个代理都使用:

  • 广播组 将有关其集群连接的信息推送到集群的其他潜在成员。
  • 用于接收和存储集群中其他代理的群集连接信息 的发现组
静态发现

如果您的网络无法使用 UDP 或 JGroups,或者您想要手动指定集群的每个成员,您可以使用静态发现。在此方法中,代理通过连接到第二个代理并发送其连接详情来"加入"集群。然后,第二个代理会将这些详情传播到集群中的其他代理。

14.1.7. 集群大小注意事项

在创建代理集群前,请考虑您的消息传递吞吐量、拓扑和高可用性要求。这些因素会影响集群中要包含的代理数量。

注意

创建集群后,您可以通过添加和删除代理来调整大小。您可以在不丢失任何消息的情况下添加和删除代理。

消息传递吞吐量

集群应包含足够代理,以提供您需要的消息传递吞吐量。集群中的更多代理,其吞吐量越大。但是,大型集群可能很复杂,难以管理。

Topology

您可以创建对称集群或链集群。您选择的拓扑类型会影响您需要的代理数量。

更多信息请参阅 第 14.1.5 节 “通用代理集群拓扑”

高可用性

如果您需要高可用性(HA),请在创建集群前考虑选择 HA 策略。HA 策略会影响集群的大小,因为每个 master 代理应该至少有一个从代理。

更多信息请参阅 第 14.3 节 “实施高可用性”

14.2. 创建代理集群

您可以通过在应加入集群的每个代理中配置集群连接来创建代理集群。以太网连接定义了代理应该如何连接到其他代理。

您可以创建一个使用静态发现或动态发现(UDP 多播或 JGroups)的代理集群。

先决条件

14.2.1. 使用静态发现创建代理集群

您可以通过指定静态代理列表来创建代理集群。如果您在网络上无法使用 UDP 多播或 JGroups,可使用此静态发现方法。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 在 & lt;core > 元素中添加以下连接器:

    • 定义其他代理如何连接这个连接器
    • 定义此代理如何连接到集群中的其他代理的一个或多个连接器
    <configuration>
        <core>
            ...
            <connectors>
                <connector name="netty-connector">tcp://localhost:61617</connector>  1
                <connector name="broker2">tcp://localhost:61618</connector>  2
                <connector name="broker3">tcp://localhost:61619</connector>
            </connectors>
            ...
        </core>
    </configuration>
    1
    此连接器定义了其他代理可以用来连接这个连接的连接信息。这些信息将在发现过程中发送到集群中的其他代理。
    2
    broker2broker3 连接器定义此代理如何连接到集群中的两个其他代理,其中一个将始终可用。如果集群中有其他代理,则在进行初始连接时,这些连接器之一将发现它们。

    有关连接器的详情请参考 第 2.3 节 “关于连接器”

  3. 添加集群连接,并将其配置为使用静态发现。

    默认情况下,集群连接将负载均衡对称拓扑中所有地址的信息。

    <configuration>
        <core>
            ...
            <cluster-connections>
                <cluster-connection name="my-cluster">
                    <connector-ref>netty-connector</connector-ref>
                    <static-connectors>
                        <connector-ref>broker2-connector</connector-ref>
                        <connector-ref>broker3-connector</connector-ref>
                    </static-connectors>
                </cluster-connection>
            </cluster-connections>
            ...
        </core>
    </configuration>
    cluster-connection
    使用 name 属性指定集群状态的名称。
    connector-ref
    定义其他代理如何连接这个连接器的连接器。
    static-connectors
    此代理可用于向集群中的另一个代理进行初始连接的一个或多个连接器。在进行此初始连接后,代理将发现集群中的其他代理。只有在集群使用静态发现时,才需要配置此属性。
  4. 为集群连接配置任何其他属性。

    这些额外的集群连接属性具有适用于大多数常见用例的默认值。因此,如果不需要默认行为,您只需要配置这些属性。更多信息请参阅 附录 C, Cluster Connection Configuration Elements

  5. 创建集群用户和密码。

    AMQ Broker 附带默认集群凭证,但您应该更改它们,以防止未经授权的远程客户端使用这些默认凭证连接到代理。

    重要

    在集群的每个代理中,集群密码必须相同。

    <configuration>
        <core>
            ...
            <cluster-user>cluster_user</cluster-user>
            <cluster-password>cluster_user_password</cluster-password>
            ...
        </core>
    </configuration>
  6. 在每个附加代理中重复此步骤。

    您可以将集群配置复制到每个附加代理。但是,不要复制任何其他 AMQ Broker 数据文件(如绑定、日志和大型消息目录)。这些文件必须在集群中的节点之间唯一,否则集群将无法正确形成。

其他资源

14.2.2. 使用基于 UDP 的动态发现创建代理集群

您可以创建一个代理集群,该集群代理通过 UDP 多播动态发现彼此。

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 在 & lt;core > 元素中添加连接器。

    此连接器定义了其他代理可以用来连接这个连接的连接信息。这些信息将在发现过程中发送到集群中的其他代理。

    <configuration>
        <core>
            ...
            <connectors>
                <connector name="netty-connector">tcp://localhost:61617</connector>
            </connectors>
            ...
        </core>
    </configuration>
  3. 添加 UDP 广播组。

    广播组可让代理将有关其集群连接的信息推送到集群中的其他代理。这个广播组使用 UDP 来广播连接设置:

    <configuration>
        <core>
            ...
            <broadcast-groups>
                <broadcast-group name="my-broadcast-group">
                    <local-bind-address>172.16.9.3</local-bind-address>
                    <local-bind-port>-1</local-bind-port>
                    <group-address>231.7.7.7</group-address>
                    <group-port>9876</group-port>
                    <broadcast-period>2000</broadcast-period>
                    <connector-ref>netty-connector</connector-ref>
                </broadcast-group>
            </broadcast-groups>
            ...
        </core>
    </configuration>

    除非另有说明,否则需要以下参数:

    broadcast-group
    使用 name 属性指定广播组的唯一名称。
    local-bind-address
    UDP 套接字绑定到的地址。如果您在代理上有多个网络接口,您应该指定要用于广播的哪些网络接口。如果没有指定此属性,套接字将绑定到操作系统选择的 IP 地址。这是特定于 UDP 的属性。
    local-bind-port
    数据报报套接字绑定到的端口。在大多数情况下,使用默认值 -1,它指定匿名端口。这个参数用于与 local-bind-address 的连接。这是特定于 UDP 的属性。
    group-address
    数据将广播的多播地址。它是范围 224.0.0.0 - 239.255.255.255 中的类 D IP 地址。地址 224.0.0.0 被保留,不可用。这是特定于 UDP 的属性。
    group-port
    用于广播的 UDP 端口号。这是特定于 UDP 的属性。
    广播期间 (可选)
    连续广播间隔(以毫秒为单位)。默认值为 2000 毫秒。
    connector-ref
    之前配置的群集连接器应该被广播。
  4. 添加 UDP 发现组。

    discovery 组定义了此代理如何接收其他代理的连接器信息。代理维护一个连接器列表(每个代理一个条目)。当它从代理广播时,它会更新其条目。如果它没有从代理收到一个长度的广播,它将删除该条目。

    此发现组使用 UDP 发现集群中的代理:

    <configuration>
        <core>
            ...
            <discovery-groups>
                <discovery-group name="my-discovery-group">
                    <local-bind-address>172.16.9.7</local-bind-address>
                    <group-address>231.7.7.7</group-address>
                    <group-port>9876</group-port>
                    <refresh-timeout>10000</refresh-timeout>
                </discovery-group>
            <discovery-groups>
            ...
        </core>
    </configuration>

    除非另有说明,否则需要以下参数:

    discovery-group
    使用 name 属性指定 discovery 组的唯一名称。
    local-bind-address (可选)
    如果运行代理的机器使用多个网络接口,您可以指定发现组应侦听的网络接口。这是特定于 UDP 的属性。
    group-address
    要侦听的组的多播地址。它应该与您要侦听的广播组中的 group-address 匹配。这是特定于 UDP 的属性。
    group-port
    多播组的 UDP 端口号。它应该与您要 侦听的 广播组中的组端口匹配。这是特定于 UDP 的属性。
    refresh-timeout (可选)

    在从特定代理收到最后一次广播后,发现组在从特定代理收到最后一次广播后等待的时间长度(以毫秒为单位),然后从它列表中删除该代理的连接器对条目。默认值为 10000 毫秒(10 秒)。

    把它设置为高于 broadcast-period 在 broadcast-period 范围内的值。否则,代理可能会定期从列表中消失,即使它们仍然在广播(因为计时中的差别不同)。

  5. 创建集群连接,并将其配置为使用动态发现。

    默认情况下,集群连接将负载均衡对称拓扑中所有地址的信息。

    <configuration>
        <core>
            ...
            <cluster-connections>
                <cluster-connection name="my-cluster">
                    <connector-ref>netty-connector</connector-ref>
                    <discovery-group-ref discovery-group-name="my-discovery-group"/>
                </cluster-connection>
            </cluster-connections>
            ...
        </core>
    </configuration>
    cluster-connection
    使用 name 属性指定集群状态的名称。
    connector-ref
    定义其他代理如何连接这个连接器的连接器。
    discovery-group-ref
    此代理应使用的 discovery 组来查找集群的其他成员。只有集群使用动态发现时,才需要配置此属性。
  6. 为集群连接配置任何其他属性。

    这些额外的集群连接属性具有适用于大多数常见用例的默认值。因此,如果不需要默认行为,您只需要配置这些属性。更多信息请参阅 附录 C, Cluster Connection Configuration Elements

  7. 创建集群用户和密码。

    AMQ Broker 附带默认集群凭证,但您应该更改它们,以防止未经授权的远程客户端使用这些默认凭证连接到代理。

    重要

    在集群的每个代理中,集群密码必须相同。

    <configuration>
        <core>
            ...
            <cluster-user>cluster_user</cluster-user>
            <cluster-password>cluster_user_password</cluster-password>
            ...
        </core>
    </configuration>
  8. 在每个附加代理中重复此步骤。

    您可以将集群配置复制到每个附加代理。但是,不要复制任何其他 AMQ Broker 数据文件(如绑定、日志和大型消息目录)。这些文件必须在集群中的节点之间唯一,否则集群将无法正确形成。

其他资源

14.2.3. 使用基于 JGroups 的动态发现创建代理集群

如果您已在环境中使用 JGroups,则可使用它创建一个代理集群来动态发现每个代理。

先决条件

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 在 & lt;core > 元素中添加连接器。

    此连接器定义了其他代理可以用来连接这个连接的连接信息。这些信息将在发现过程中发送到集群中的其他代理。

    <configuration>
        <core>
            ...
            <connectors>
                <connector name="netty-connector">tcp://localhost:61617</connector>
            </connectors>
            ...
        </core>
    </configuration>
  3. 在 & lt;core > 元素中添加一个 JGroups 广播组。

    广播组可让代理将有关其集群连接的信息推送到集群中的其他代理。这个广播组使用 JGroups 广播连接设置:

    <configuration>
        <core>
            ...
            <broadcast-groups>
                <broadcast-group name="my-broadcast-group">
                    <jgroups-file>test-jgroups-file_ping.xml</jgroups-file>
                    <jgroups-channel>activemq_broadcast_channel</jgroups-channel>
                    <broadcast-period>2000</broadcast-period>
                    <connector-ref>netty-connector</connector-ref>
                </broadcast-group>
            </broadcast-groups>
            ...
        </core>
    </configuration>

    除非另有说明,否则需要以下参数:

    broadcast-group
    使用 name 属性指定广播组的唯一名称。
    jgroups-file
    用于初始化 JGroups 通道的Groups 配置文件的名称。该文件必须位于 Java 资源路径中,以便代理可以加载它。
    jgroups-channel
    要连接到 的Groups 频道的名称,用于广播。
    广播期间 (可选)
    连续广播间隔(以毫秒为单位)。默认值为 2000 毫秒。
    connector-ref
    之前配置的群集连接器应该被广播。
  4. 添加Groups 发现组。

    discovery 组定义了连接器信息是如何被接收的。代理维护一个连接器列表(每个代理一个条目)。当它从代理广播时,它会更新其条目。如果它没有从代理收到一个长度的广播,它将删除该条目。

    此发现组使用 JGroups 发现集群中的代理:

    <configuration>
        <core>
            ...
            <discovery-groups>
                <discovery-group name="my-discovery-group">
                    <jgroups-file>test-jgroups-file_ping.xml</jgroups-file>
                    <jgroups-channel>activemq_broadcast_channel</jgroups-channel>
                    <refresh-timeout>10000</refresh-timeout>
                </discovery-group>
            <discovery-groups>
            ...
        </core>
    </configuration>

    除非另有说明,否则需要以下参数:

    discovery-group
    使用 name 属性指定 discovery 组的唯一名称。
    jgroups-file
    用于初始化 JGroups 通道的Groups 配置文件的名称。该文件必须位于 Java 资源路径中,以便代理可以加载它。
    jgroups-channel
    要连接到 的Groups 频道的名称以接收广播。
    refresh-timeout (可选)

    在从特定代理收到最后一次广播后,发现组在从特定代理收到最后一次广播后等待的时间长度(以毫秒为单位),然后从它列表中删除该代理的连接器对条目。默认值为 10000 毫秒(10 秒)。

    把它设置为高于 broadcast-period 在 broadcast-period 范围内的值。否则,代理可能会定期从列表中消失,即使它们仍然在广播(因为计时中的差别不同)。

  5. 创建集群连接,并将其配置为使用动态发现。

    默认情况下,集群连接将负载均衡对称拓扑中所有地址的信息。

    <configuration>
        <core>
            ...
            <cluster-connections>
                <cluster-connection name="my-cluster">
                    <connector-ref>netty-connector</connector-ref>
                    <discovery-group-ref discovery-group-name="my-discovery-group"/>
                </cluster-connection>
            </cluster-connections>
            ...
        </core>
    </configuration>
    cluster-connection
    使用 name 属性指定集群状态的名称。
    connector-ref
    定义其他代理如何连接这个连接器的连接器。
    discovery-group-ref
    此代理应使用的 discovery 组来查找集群的其他成员。只有集群使用动态发现时,才需要配置此属性。
  6. 为集群连接配置任何其他属性。

    这些额外的集群连接属性具有适用于大多数常见用例的默认值。因此,如果不需要默认行为,您只需要配置这些属性。更多信息请参阅 附录 C, Cluster Connection Configuration Elements

  7. 创建集群用户和密码。

    AMQ Broker 附带默认集群凭证,但您应该更改它们,以防止未经授权的远程客户端使用这些默认凭证连接到代理。

    重要

    在集群的每个代理中,集群密码必须相同。

    <configuration>
        <core>
            ...
            <cluster-user>cluster_user</cluster-user>
            <cluster-password>cluster_user_password</cluster-password>
            ...
        </core>
    </configuration>
  8. 在每个附加代理中重复此步骤。

    您可以将集群配置复制到每个附加代理。但是,不要复制任何其他 AMQ Broker 数据文件(如绑定、日志和大型消息目录)。这些文件必须在集群中的节点之间唯一,否则集群将无法正确形成。

其他资源

14.3. 实施高可用性

您可以通过实施高可用性(HA)来提高可靠性,即使一个或多个代理离线,代理集群也会继续运行。

实施 HA 涉及几个步骤:

  1. 为您的 HA 实现配置代理集群,如 第 14.2 节 “创建代理集群” 所述。
  2. 您应该了解 live-backup 组是什么,并选择一个最适合您的要求的 HA 策略。请参阅了解 HA 在 AMQ Broker 中如何工作
  3. 当您选择了适当的 HA 策略时,请在集群中的每个代理中配置 HA 策略。请参阅:

  4. 配置客户端应用程序以使用故障转移
注意

在稍后需要对代理进行高可用性配置的代理集群进行故障排除时,建议您为运行代理的每个 Java Virtual Machine(JVM)实例启用 Garbage Collection(GC)日志记录。要了解如何在 JVM 上启用 GC 日志,请参阅您的 JVM 使用的 Java Development Kit(JDK)版本的官方文档。有关 AMQ Broker 支持的 JVM 版本的更多信息,请参阅 Red Hat AMQ 7 支持的配置

14.3.1. 了解高可用性

在 AMQ Broker 中,您可以通过将集群中的代理分组到 live-backup groups 来实现高可用性(HA)。在 live-backup 组中,实时代理链接到备份代理,如果实时代理失败,则可接管该代理。AMQ Broker 还提供了几个不同的策略,用于实时备份组内故障转移(称为 HA 策略)。

14.3.1.1. 实时备份组如何提供高可用性

在 AMQ Broker 中,您可以通过将集群中的代理链接在一起以组成 live-backup 组 来实现高可用性(HA)。live-backup 组提供 故障切换,这意味着如果一个代理失败,另一个代理可以接管其消息处理。

live-backup 组由一个实时代理(有时也称为 代理)组成,链接到一个或多个备份代理(有时称为代理)。实时代理提供客户端请求,而备份代理则以被动模式等待。如果 live 代理失败,备份代理会替换 live 代理,使客户端可以重新连接并继续工作。

14.3.1.2. 高可用性策略

高可用性(HA)策略定义在 live-backup 组中进行故障转移的方式。AMQ Broker 提供几个不同的 HA 策略:

共享存储(推荐)

实时和备份代理将其消息传递数据存储在共享文件系统中的通用目录中;通常是存储区域网络(SAN)或网络文件系统(NFS)服务器。如果您配置了基于 JDBC 的持久性,您也可以将代理数据存储在指定的数据库中。使用共享存储时,如果实时代理失败,备份代理会从共享存储中加载消息数据,并接管了失败的实时代理。

在大多数情况下,您应该使用共享存储而不是复制。由于共享存储不会通过网络复制数据,它通常比复制提供更好的性能。共享存储还可避免网络隔离(也称为 "split brain")问题,其中实时代理及其备份会同时变为现实。

在共享存储 HA 策略中,实时和备份代理同时访问共享位置的日志。
复制

实时和备份代理在网络上持续同步其消息传递数据。如果 live 代理失败,备份代理会加载同步数据,并为失败的实时代理接管。

实时和备份代理之间的数据同步可确保当实时代理失败时不会丢失消息数据。当实时和备份代理最初加入到一起时,实时代理通过网络将所有现有数据复制到备份代理。完成此初始阶段后,实时代理会将持久数据复制到备份代理中,因为实时代理接收它。这意味着,如果实时代理丢弃了网络,备份代理具有实时代理接收至该点的所有持久性数据。

因为复制通过网络同步数据,所以网络故障可能会导致实时代理及其备份同时变为实时的网络隔离。

在复制 HA 策略中,实时和备份代理会将它们的日志与网络相互同步。
仅实时(仅限 HA 限制)

当实时代理安全停止时,它会将信息及事务状态复制到另一个实时代理,然后关闭。然后,客户端可以重新连接其他代理,以继续发送和接收消息。

在 live-only HA 策略中,代理会将其信息及事务状态复制到另一个代理中。

其他资源

14.3.1.3. 复制策略限制

当您使用复制来提供高可用性时,实时迁移和备份代理可以同时处于活动状态,这称为"脑裂"。

如果实时代理及其备份丢失了连接,则脑裂可能发生。在这种情况下,实时代理及其备份可以同时处于活动状态。因为在这种情况下,代理之间没有消息复制,所以它们会在没有其他知道它的情况下服务客户端和处理信息。在这种情况下,每个代理都有完全不同的日志。从这种情形中进行恢复可能非常困难,在某些情况下无法进行恢复。

  • 消除 脑裂的可能性,请使用 共享存储 HA 策略。
  • 如果您使用复制 HA 策略,请执行以下步骤以减少分区发生的风险。

    如果您希望代理使用 ZooKeeper Coordination Service 协调代理,请在至少三个节点上部署 ZooKeeper。如果代理丢失到一个 ZooKeeper 节点,使用至少三个节点可确保当实时备份代理对造成复制中断时,大多数节点都可用来协调代理。

    如果要使用嵌入式代理协调,它使用集群中的其他可用代理提供仲裁投票,这可以减少(但不会完全消除)遇到脑裂的可能性(最少三个 live-backup 对)。使用至少三个 live-backup 对可确保当实时备份代理对遇到复制中断时,任何仲裁投票都会获得多数结果。

使用复制 HA 策略时需要考虑一些额外的注意事项:

  • 当实时代理失败并且备份转换为实时时,不会进行进一步复制,直到新的备份代理附加到实时,或者会恢复到原始 live 代理。
  • 如果 live-backup 组中的备份代理失败,则 live 代理将继续提供消息。但是,在另一个代理添加为备份之前,消息不会被复制,或者重启原始备份代理。在此期间,信息只映射到 live 代理。
  • 如果代理使用嵌入的代理协调,且在实时备份对中的代理都已关闭,为了避免消息丢失,您必须首先重启最近活跃的代理。如果最近活跃的代理是备份代理,则需要手动将此代理重新配置为主代理,以便首先重启该代理。

14.3.2. 配置共享存储高可用性

您可以使用共享存储高可用性(HA)策略在代理集群中实现 HA。使用共享存储时,实时和备份代理访问共享文件系统上的通用目录;通常是 Storage Area Network(SAN)或网络文件系统(NFS)服务器。如果您配置了基于 JDBC 的持久性,您也可以将代理数据存储在指定的数据库中。使用共享存储时,如果实时代理失败,备份代理会从共享存储中加载消息数据,并接管了失败的实时代理。

通常,SAN 提供更好的性能(例如,速度)与 NFS 服务器,如果可用,则建议选择。如果您需要使用 NFS 服务器,请参阅 Red Hat AMQ 7 支持的配置。有关 AMQ Broker 支持的网络文件系统的更多信息。

在大多数情况下,您应该使用共享存储 HA 而不是复制。由于共享存储不会通过网络复制数据,它通常比复制提供更好的性能。共享存储还可避免网络隔离(也称为 "split brain")问题,其中实时代理及其备份会同时变为现实。

注意

在使用共享存储时,备份代理的启动时间取决于消息日志的大小。当备份代理接管失败的实时代理时,它会从共享存储中加载日志。如果日志包含大量数据,这个过程可能会消耗大量时间。

14.3.2.1. 配置 NFS 共享存储

使用共享存储高可用性时,您必须将 live 和 backup 代理配置为使用共享文件系统上的通用目录。通常,您使用 Storage Area Network(SAN)或网络文件系统(NFS)服务器。

在每个代理机器实例上从 NFS 服务器挂载导出的目录时,列出了以下一些推荐的配置选项。

sync
指定所有更改都会立即冲刷到磁盘。
intr
如果服务器关闭或无法访问,允许中断 NFS 请求。
noac
禁用属性缓存。需要在多个客户端间实现属性缓存一致性。
soft
指定如果 NFS 服务器不可用,应该报告错误,而不是等待服务器重新上线。
lookupcache=none
禁用查询缓存。
timeo=n
NFS 客户端(如代理)在重试请求前等待来自 NFS 服务器的响应(以毫秒为单位)。对于通过 TCP 的 NFS,默认的 timeo 值为 600 (60 秒)。对于通过 UDP 的 NFS,客户端使用一种适应性算法来估算常用请求类型的适当超时值,如读写请求。
retrans=n
NFS 客户端在尝试进一步恢复操作前重试请求的次数。如果没有指定 retrans 选项,则 NFS 客户端会尝试每个请求三次。
重要

配置 timeoretrans 选项时,务必要使用合理的值。一个默认的 timeo 等待时间为 600 deciseconds(60 秒),retrans 值为 5(重试 5 次),可能会导致 AMQ Broker 需要 5 分钟的等待时间来检测到一个 NFS 已断开连接。

其他资源

14.3.2.2. 配置共享存储高可用性

此流程演示了如何为代理集群配置共享存储高可用性。

先决条件

  • live 和 backup 代理必须可以访问共享存储系统。

流程

  1. 将集群中的代理分组到 live-backup 组。

    在大多数情况下,live-backup 组应该包含两个代理:一个实时代理和备份代理。如果集群中有六个代理,则需要三个 live-backup 组。

  2. 创建由一个 live 代理和一个备份代理组成的第一个 live-backup 组。

    1. 打开 live 代理的 < broker_instance_dir&gt; /etc/broker.xml 配置文件。
    2. 如果使用:

      1. 用于提供共享存储的网络文件系统,验证实时代理的分页、绑定、日志和大量消息目录指向备份代理也可以访问的共享位置。

        <configuration>
            <core>
                ...
                <paging-directory>../sharedstore/data/paging</paging-directory>
                <bindings-directory>../sharedstore/data/bindings</bindings-directory>
                <journal-directory>../sharedstore/data/journal</journal-directory>
                <large-messages-directory>../sharedstore/data/large-messages</large-messages-directory>
                ...
            </core>
        </configuration>
      2. 提供共享存储的数据库,确保 master 和备份代理都可以连接到同一数据库,并在 broker.xml 配置文件的 database-store 元素中指定相同的配置。下面是一个配置示例。

        <configuration>
          <core>
            <store>
               <database-store>
                  <jdbc-connection-url>jdbc:oracle:data/oracle/database-store;create=true</jdbc-connection-url>
                  <jdbc-user>ENC(5493dd76567ee5ec269d11823973462f)</jdbc-user>
                  <jdbc-password>ENC(56a0db3b71043054269d11823973462f)</jdbc-password>
                  <bindings-table-name>BIND_TABLE</bindings-table-name>
                  <message-table-name>MSG_TABLE</message-table-name>
                  <large-message-table-name>LGE_TABLE</large-message-table-name>
                  <page-store-table-name>PAGE_TABLE</page-store-table-name>
                  <node-manager-store-table-name>NODE_TABLE<node-manager-store-table-name>
                  <jdbc-driver-class-name>oracle.jdbc.driver.OracleDriver</jdbc-driver-class-name>
                  <jdbc-network-timeout>10000</jdbc-network-timeout>
                  <jdbc-lock-renew-period>2000</jdbc-lock-renew-period>
                  <jdbc-lock-expiration>15000</jdbc-lock-expiration>
                  <jdbc-journal-sync-period>5</jdbc-journal-sync-period>
               </database-store>
            </store>
          </core>
        </configuration>
    3. 将实时代理配置为使用共享存储作为其 HA 策略。

      <configuration>
          <core>
              ...
              <ha-policy>
                  <shared-store>
                      <master>
                          <failover-on-shutdown>true</failover-on-shutdown>
                      </master>
                  </shared-store>
              </ha-policy>
              ...
          </core>
      </configuration>
      failover-on-shutdown
      如果此代理正常停止,则此属性会控制备份代理是否应该处于活动状态并接管。
    4. 打开备份代理的 < broker_instance_dir&gt; /etc/broker.xml 配置文件。
    5. 如果使用:

      1. 提供共享存储的网络文件系统,验证备份代理的分页、绑定、日志和大型消息目录指向与实时代理相同的共享位置。

        <configuration>
            <core>
                ...
                <paging-directory>../sharedstore/data/paging</paging-directory>
                <bindings-directory>../sharedstore/data/bindings</bindings-directory>
                <journal-directory>../sharedstore/data/journal</journal-directory>
                <large-messages-directory>../sharedstore/data/large-messages</large-messages-directory>
                ...
            </core>
        </configuration>
      2. 提供共享存储的数据库,确保 master 和备份代理都可以连接到同一数据库,并在 broker.xml 配置文件的 database-store 元素中指定相同的配置。
    6. 将备份代理配置为使用共享存储作为其 HA 策略。

      <configuration>
          <core>
              ...
              <ha-policy>
                  <shared-store>
                      <slave>
                          <failover-on-shutdown>true</failover-on-shutdown>
                          <allow-failback>true</allow-failback>
                          <restart-backup>true</restart-backup>
                      </slave>
                  </shared-store>
              </ha-policy>
              ...
          </core>
      </configuration>
      failover-on-shutdown
      如果此代理已变为 live 状态,然后正常停止,此属性会控制备份代理(原始实时代理)是否应该变为实时状态并接管。
      allow-failback

      如果发生了故障转移,并且备份代理已接管了实时代理,则此属性会控制备份代理是否在重启并重新连接到集群中时是否应该回退到原始的 live 代理。

      注意

      故障恢复用于实时备份对(一个与单一备份代理进行一对一的代理)。如果 live 代理配置了多个备份,则不会出现问题。如果发生故障转移事件,备份代理将变为 live 状态,下一次备份就成为其备份。当原始 live 代理恢复在线时,它无法启动故障,因为现在已经备份的代理已经有备份。

      restart-backup
      此属性控制备份代理在返回到实时代理失败后是否自动重启。此属性的默认值为 true
  3. 对集群中的每个剩余的 live-backup 组重复步骤 2。

14.3.3. 配置复制高可用性

您可以使用复制高可用性(HA)策略在代理集群中实施 HA。使用复制时,持久数据会在实时和备份代理之间同步。如果实时代理遇到失败,则会将消息数据同步到备份代理中,并为失败的实时代理接管。

如果没有共享文件系统,您应该使用复制作为共享存储的替代选择。但是,复制可能会导致一个场景中实时代理及其备份。

注意

因为 live 和 backup 代理必须通过网络同步其消息传递数据,所以复制会增加性能开销。此同步进程块日志操作,但它不会阻止客户端。对于数据同步,您可以配置可阻止日志操作的最长时间。

如果 live-backup 代理对间的复制连接中断,代理需要协调一个方法来确定实时代理是否仍活跃,或者是否不可用,且需要故障转移到备份代理。要提供此协调过程,您可以将代理配置为使用以下任意一种:

  • Apache ZooKeeper 协调服务。
  • 嵌入式代理协调,它使用集群中的其他代理提供仲裁投票。
14.3.3.1. 选择协调方法

您可以将代理配置为使用 ZooKeeper 协调服务或嵌入式代理协调服务,以确定复制中断时是否需要故障转移。本节介绍基础架构要求,以及这两种方法管理数据一致性之间的区别,这是选择协调方法时可能出现的注意事项。

基础架构要求

  • 如果您希望代理使用 ZooKeeper 协调服务,您必须将代理连接到至少 3 个 Apache ZooKeeper 节点。至少 3 个 ZooKeeper 节点,如果代理丢失到一个节点的连接,则可以继续正常工作。要为代理提供协调服务,您可以共享由其他应用程序使用的现有 ZooKeeper 节点。有关设置 Apache ZooKeeper 的更多信息,请参阅 Apache ZooKeeper 文档。
  • 如果要使用嵌入式代理协调(使用集群中的其他可用代理)提供仲裁投票,则必须至少有三个实时备份代理对。至少使用三个实时备份对可确保当实时备份代理对造成复制中断时,会发生大多数结果。

数据一致性

  • 如果您使用 Apache ZooKeeper 协调服务,ZooKeeper 跟踪每个代理上的数据版本,因此只有具有最新日志数据的代理才能作为实时代理激活,无论代理是否配置为复制目的。版本跟踪消除了代理可通过过期日志和启动客户端激活的可能性。
  • 如果您使用嵌入的代理协调,则不存在相应的机制来跟踪每个代理中的数据版本,以确保只有具有最新日志的代理即可成为实时代理。因此,具有过时日志的代理可能会成为实时和启动客户端,这会导致在日志中发生冲突。
14.3.3.2. 在复制中断后代理如何协调

本节介绍在复制连接中断后如何工作协调方法。

使用 ZooKeeper 协调服务

如果使用 ZooKeeper 协调服务来管理复制中断,则两个代理必须连接到多个 Apache ZooKeeper 节点。

  • 如果有任何时候,实时代理都会丢失到大多数 ZooKeeper 节点的连接,它会关闭以避免发生 "plit brain" 的风险。
  • 如果有任何时候,备份代理会丢失到大多数 ZooKeeper 节点的连接,它会停止接收复制数据并等待其连接大多数 ZooKeeper 节点,然后再重新作为备份代理。当连接恢复到大多数 ZooKeeper 节点时,备份代理使用 ZooKeeper 来确定是否需要丢弃其数据并从中搜索实时代理,或者是否可使用其当前数据成为实时代理。

zookeeper 使用以下控制机制来管理故障切换过程:

  • 共享租期锁定,随时只能由单一实时代理所有。
  • 跟踪代理数据的最新版本的激活序列计数器。每个代理跟踪其日志数据在本地计数器中的版本,保存在其服务器锁定文件中,及其 NodeID。实时代理还在 ZooKeeper 上的协调激活序列计数器中共享其版本。

如果 live 代理和备份代理之间的复制连接丢失,则 live 代理会同时增加其本地激活序列计数器值,并在 ZooKeeper 上增加协调激活序列计数器值(1)来公告它具有最新数据。备份代理的数据现在被视为过时的数据,在复制连接被恢复并且同步最新的数据前,代理无法变为实时代理。

在复制连接丢失后,备份代理会检查 ZooKeeper 锁定是否归 live 代理所有,如果 ZooKeeper 协调激活序列计数器与本地计数器值匹配。

  • 如果锁定归 live 代理所有,则备份代理检测到在复制连接丢失时由 live 代理更新 ZooKeeper 上的激活序列计数器。这表示 live 代理正在运行,因此备份代理不会尝试故障切换。备份代理会搜索实时代理来复制数据,使其具有最新数据。
  • 如果锁定没有由 live 代理所有,则实时代理不可用。如果备份代理上的激活序列计数器的值与 ZooKeeper 上的协调激活序列计数器值相同,这表示备份代理具有最新数据,备份代理将会失败。
  • 如果锁定不归 live 代理所有,但备份代理中的激活序列计数器的值小于 ZooKeeper 上的计数器值,则备份代理中的数据不会被更新,且备份代理无法失败。

使用嵌入的代理协调

如果实时备份代理对使用嵌入式代理协调协调复制中断,可以启动以下两类仲裁投票。

投票类型描述initiator所需配置参与者基于投票结果的操作

备份投票

如果备份代理丢失了与实时代理的复制连接,备份代理会根据这个投票的结果来决定是否启动。

备份代理

无。备份代理丢失与其复制合作伙伴的连接时,自动进行备份投票。

但是,您可以通过为这些参数指定自定义值来控制备份投票的属性:

  • quorum-vote-wait
  • vote-retries
  • vote-retry-wait

集群中的其他实时代理

如果备份代理收到来自集群中其他 live Broker 的投票,则会启动备份代理(即 仲裁)投票,表示其复制合作伙伴不再可用。

实时投票

如果实时代理丢失了与其复制合作伙伴的连接,则实时代理会决定根据这个投票继续运行。

实时代理

当实时代理丢失与复制合作伙伴的连接并将 vote-on-replication-failure 设置为 true 时,会出现实时投票功能。已成为活跃的备份代理被视为实时代理,并可以启动实时投票。

集群中的其他实时代理

如果实时代理 没有 从集群中的其他实时代理收到多数投票,代表其 cluster connection 仍活跃,则会关闭它。

重要

下面列出了一些重要事项,需要注意如何配置代理集群会影响仲裁投票的行为。

  • 要使仲裁投票方可成功,集群的大小必须允许实现多数结果。因此,您的集群应该 至少有三个 实时备份代理对。
  • 添加到集群中的 live-backup 代理对越大,您可以增加集群的整体容错功能。例如,假设您有三个实时备份对。如果您丢失了完整的 live-backup 对,则两个剩余的实时备份对无法实现多数结果,后续的仲裁投票。这种情况意味着,集群中的任何进一步复制中断都可能会导致实时代理关闭,并防止备份代理启动。通过使用配置集群(如五个代理对),集群可能会至少出现两个故障,同时仍然保证所有仲裁投票中多数结果。
  • 如果您有意 减少 集群中实时备份代理对的数量,则以前建立的阈值不会自动减少。在此期间,丢失复制连接触发的任何仲裁投票都无法成功,从而使集群容易受到脑裂的影响。要使集群重新计算仲裁投票的大多数阈值,首先关闭您要从集群中移除的 live-backup 对。然后,重启集群中剩余的 live-backup 对。当所有剩余的代理都已重启时,集群会重新计算仲裁投票阈值。
14.3.3.3. 配置代理集群以使用 ZooKeeper 协调服务复制高可用性

以下流程描述了如何为使用 Apache ZooKeeper 协调服务的代理集群配置复制高可用性(HA)。

先决条件

  • 至少 3 个 Apache ZooKeeper 节点,确保在代理丢失到一个节点时,代理可以继续运行。
  • zookeeper 必须有足够的资源来确保暂停时间明显小于 ZooKeeper 服务器空循环时间。根据代理的预期负载,请仔细考虑代理和 ZooKeeper 节点是否应该共享相同的节点。如需更多信息,请参阅 https://zookeeper.apache.org/

流程

  1. 使用 ZooKeeper 协调服务,将实时代理配置为使用复制高可用性。

    1. 打开 live 代理的 < broker_instance_dir&gt; /etc/broker.xml 配置文件。
    2. 将实时代理配置为使用复制作为其 HA 策略。

      <configuration>
          <core>
              ...
              <ha-policy>
                  <replication>
                      <primary>
                          <manager>
                          ...
                          </manager>
                            <group-name>my-group-1</group-name>
                      </primary>
                  </replication>
              </ha-policy>
              ...
          </core>
      </configuration>
      主要
      表示此代理在初始配置后作为 live 代理启动。
      group-name
      此 live-backup 组的名称(可选)。要形成 live-backup 组,必须使用相同的组名称和备份代理配置 live-backup 代理。如果您没有指定 group-name,备份代理可以使用任何实时代理复制。
    3. manager 部分,配置属性,将 live 代理连接到 ZooKeeper 节点。

      <configuration>
          <core>
              ...
              <ha-policy>
                  <replication>
                      <primary>
                          <manager>
                              <class-name>org.apache.activemq.artemis.quorum.zookeeper.CuratorDistributedPrimitiveManager</class-name>
                              <properties>
                                  <property key="connect-string" value="192.168.1.10:6666,192.168.2.10:6667,192.168.3.10:6668"/>
                              </properties>
                          </manager>
                      ...
                      </primary>
                  </replication>
              </ha-policy>
              ...
          </core>
      </configuration>
      class-name
      ZooKeeper 协调服务的类名称: org.apache.activemq.artemis.quorum.zookeeper.CuratorDistributedPrimitiveManager.如果 Apache Curator 是默认管理器,则此元素是可选的。
      属性

      指定 property 元素,您可以指定一组键值对,以提供 ZooKeeper 节点的连接详情:

      connect-string

      为实时代理指定 ZooKeeper 节点的 IP 地址和端口号的逗号分隔列表。例如,value="192.168.1.10:6666,192.168.2.10:6667,192.168.3.10:6668".

      session-ms

      实时代理在丢失到大多数 ZooKeeper 节点的连接后,等待的持续时间。默认值为 18000 ms。有效值是 ZooKeeper 服务器循环时间的 2 次和 20 倍。

      注意

      垃圾回收的 ZooKeeper 暂停时间必须小于 session-ms 属性的值的 0.33,以便 ZooKeeper heartbeat 能够可靠地工作。如果无法确保暂停时间小于这个限制,请增加每个代理的 session-ms 属性的值,并接受较慢的故障转移。

      重要

      代理复制合作伙伴每 2 秒自动交换"ping"数据包,以确认合作伙伴代理可用。当备份代理没有收到来自 live 代理的响应时,备份会等待响应,直到代理的连接时间到实时(ttl)过期为止。默认 connection-ttl 为 60000 ms,这意味着备份代理会在 60 秒后尝试故障切换。建议您将 connection-ttl 值设置为与 session-ms 属性值类似,以便加快故障转移。要设置新的 connection-ttl,请配置 connection-ttl-override 属性。

      namespace(可选)

      如果代理与其他应用程序共享 ZooKeeper 节点,您可以创建一个 ZooKeeper 命名空间来存储为代理提供协调服务的文件。如果为备份代理指定命名空间,您必须为 live 代理指定相同的命名空间。

    4. 为实时代理配置任何其他 HA 属性。

      这些额外的 HA 属性具有适用于大多数常见用例的默认值。因此,如果不需要默认行为,您只需要配置这些属性。更多信息请参阅 附录 F, 额外的复制高可用性配置元素

  2. 使用 ZooKeeper 协调服务将备份代理配置为使用复制高可用性。

    1. 打开备份代理的 < broker_instance_dir&gt; /etc/broker.xml 配置文件。
    2. 配置备份代理以使用复制作为其 HA 策略。

      <configuration>
          <core>
              ...
              <ha-policy>
                  <replication>
                      <backup>
                          <manager>
                           ...
                          </manager>
                          <group-name>my-group-1</group-name>
                          <allow-failback>true</allow-failback>
                       </backup>
                  </replication>
              </ha-policy>
              ...
          </core>
      </configuration>
      backup
      表示此代理在初始配置后作为备份代理启动。
      group-name
      此备份连接的 live 代理的组名称。备份代理仅连接到共享相同组名称的 live 代理。如果您没有指定 group-name,备份代理可以使用任何实时代理复制。
      allow-failback

      如果设置为 true,则允许当前实时代理的备份代理,将实时角色返回至其复制合作伙伴,后者配置为主代理。

      当配置为实时(主)代理的代理启动时,它会检查它是否有最新的数据,并可作为实时代理运行。如果它确定其数据不是最新的,则代理会重启一个空日志,并等待连接当前实时代理来复制最新数据。在代理配置为复制数据的主代理后,它会要求备份代理(当前处于活动状态),以便重启,以便它能够故障转移并再次成为实时代理。

      如果 allow-failback 设为 true,则备份代理会重新启动,以便其复制合作伙伴再次上线。如果将 allow-failback 设为 false,则备份代理不会重启,因此两个代理都保持其当前角色。

    3. manager 部分,配置属性以将备份代理连接到 ZooKeeper 节点。

      <configuration>
          <core>
              ...
              <ha-policy>
                  <replication>
                      <backup>
                          <manager>
                              <class-name>org.apache.activemq.artemis.quorum.zookeeper.CuratorDistributedPrimitiveManager</class-name>
                              <properties>
                                  <property key="connect-string" value="192.168.1.10:6666,192.168.2.10:6667,192.168.3.10:6668"/>
                              </properties>
                          </manager>
                      ...
                      </backup>
                  </replication>
              </ha-policy>
              ...
          </core>
      </configuration>
      class-name
      ZooKeeper 协调服务的类名称: org.apache.activemq.artemis.quorum.zookeeper.CuratorDistributedPrimitiveManager.如果 Apache Curator 是默认管理器,则此元素是可选的。
      属性

      指定 属性 部分,您可以在其中指定一组键值对,以提供 ZooKeeper 节点的连接详情:

      connect-string

      为备份代理指定 ZooKeeper 节点的 IP 地址和端口号的逗号分隔列表。例如,value="192.168.1.10:6666,192.168.2.10:6667,192.168.3.10:6668".

      session-ms

      实时代理在丢失到大多数 ZooKeeper 节点的连接后,等待的持续时间。默认值为 18000 ms。有效值是 ZooKeeper 服务器循环时间的 2 次和 20 倍。

      注意

      垃圾回收的 ZooKeeper 暂停时间必须小于 session-ms 属性的值的 0.33,以便 ZooKeeper heartbeat 能够可靠地工作。如果无法确保暂停时间小于这个限制,请增加每个代理的 session-ms 属性的值,并接受较慢的故障转移。

      重要

      代理复制合作伙伴每 2 秒自动交换"ping"数据包,以确认合作伙伴代理可用。当备份代理没有收到来自 live 代理的响应时,备份会等待响应,直到代理的连接时间到实时(ttl)过期为止。默认 connection-ttl 为 60000 ms,这意味着备份代理会在 60 秒后尝试故障切换。建议您将 connection-ttl 值设置为与 session-ms 属性值类似,以便加快故障转移。要设置新的 connection-ttl,请配置 connection-ttl-override 属性。

      namespace(可选)

      如果代理与其他应用程序共享 ZooKeeper 节点,您可以创建一个 ZooKeeper 命名空间来存储为代理提供协调服务的文件。如果为备份代理指定命名空间,您必须为 live 代理指定相同的命名空间。

    4. 为备份代理配置任何其他 HA 属性。

      这些额外的 HA 属性具有适用于大多数常见用例的默认值。因此,如果不需要默认行为,您只需要配置这些属性。更多信息请参阅 附录 F, 额外的复制高可用性配置元素

  3. 重复步骤 1 和 2 以在集群中配置每个额外的实时备份代理对。

其他资源

14.3.3.4. 配置代理集群以使用嵌入式代理协调复制高可用性

使用嵌入式代理协调复制至少需要三个实时备份对,以减少(但不消除)"脑裂"的风险。

以下流程描述了如何为 6-broker 集群配置复制高可用性(HA)。在此拓扑中,6 个代理被分组到三个 live-backup 对中:三个实时代理都使用专用的备份代理来对。

先决条件

  • 您必须有一个至少 6 个代理的代理集群。

    六个代理配置为三个 live-backup 对。有关在集群中添加代理的更多信息,请参阅 第 14 章 设置代理集群

流程

  1. 将集群中的代理分组到 live-backup 组。

    在大多数情况下,live-backup 组应该包含两个代理:一个实时代理和备份代理。如果集群中有六个代理,则需要三个 live-backup 组。

  2. 创建由一个 live 代理和一个备份代理组成的第一个 live-backup 组。

    1. 打开 live 代理的 < broker_instance_dir&gt; /etc/broker.xml 配置文件。
    2. 将实时代理配置为使用复制作为其 HA 策略。

      <configuration>
          <core>
              ...
              <ha-policy>
                  <replication>
                      <master>
                          <check-for-live-server>true</check-for-live-server>
                          <group-name>my-group-1</group-name>
                          <vote-on-replication-failure>true</vote-on-replication-failure>
                          ...
                      </master>
                  </replication>
              </ha-policy>
              ...
          </core>
      </configuration>
      check-for-live-server

      如果 live 代理失败,此属性会控制客户端在重启时是否应该会失败。

      如果将此属性设置为 true,当实时代理在之前的故障切换后重启时,它会搜索集群中具有相同节点 ID 的另一个代理。如果 live 代理发现另一个具有相同节点 ID 的代理,这表示备份代理在实时代理失败时成功启动。在这种情况下,实时代理将其数据与备份代理同步。然后,实时代理请求要关闭备份代理。如果为故障恢复配置了备份代理,如下所示,它会关闭。然后,实时代理恢复其活跃角色,客户端会重新连接它。

      警告

      如果您没有在 live 代理上将 check-for-server 设置为 true,在之前的故障切换后重启 live 代理时可能会遇到重复的消息处理。具体来说,如果您重启了这个属性设置为 false 的 live 代理,则 live 代理不会将数据与备份代理同步。在这种情况下,实时代理可能会处理备份代理已处理的相同信息,从而导致重复。

      group-name
      此 live-backup 组的名称(可选)。要形成 live-backup 组,必须使用相同的组名称和备份代理配置 live-backup 代理。如果您没有指定 group-name,备份代理可以使用任何实时代理复制。
      vote-on-replication-failure

      这个属性控制实时代理在中断复制连接时是否启动了一个称为 实时投票 的仲裁投票。

      实时投票是实时代理以确定其合作伙伴是否是中断复制连接的原因。根据投票结果,实时代理会继续运行或关闭。

      重要

      要使仲裁投票方可成功,集群的大小必须允许实现多数结果。因此,当您使用 replication HA 策略时,您的集群应该 至少有三个 实时备份代理对。

      您在集群中配置的代理对越大,您可以增加集群的整体容错功能。例如,假设您有三个 live-backup 代理对。如果您丢失了到完全 live-backup 对的连接,则两个剩余的实时备份对不再实现多数结果仲裁投票。这种情况意味着,任何后续复制中断都可能会导致实时代理关闭,并阻止备份代理启动。通过使用配置集群(如五个代理对),集群可能会至少出现两个故障,同时仍然保证所有仲裁投票中多数结果。

    3. 为实时代理配置任何其他 HA 属性。

      这些额外的 HA 属性具有适用于大多数常见用例的默认值。因此,如果不需要默认行为,您只需要配置这些属性。更多信息请参阅 附录 F, 额外的复制高可用性配置元素

    4. 打开备份代理的 < broker_instance_dir&gt; /etc/broker.xml 配置文件。
    5. 配置备份代理以使用复制作为其 HA 策略。

      <configuration>
          <core>
              ...
              <ha-policy>
                  <replication>
                      <slave>
                          <allow-failback>true</allow-failback>
                          <group-name>my-group-1</group-name>
                          <vote-on-replication-failure>true</vote-on-replication-failure>
                          ...
                      </slave>
                  </replication>
              </ha-policy>
              ...
          </core>
      </configuration>
      allow-failback

      如果发生了故障转移,并且备份代理已接管了实时代理,则此属性会控制备份代理是否在重启并重新连接到集群中时是否应该回退到原始的 live 代理。

      注意

      故障恢复用于实时备份对(一个与单一备份代理进行一对一的代理)。如果 live 代理配置了多个备份,则不会出现问题。如果发生故障转移事件,备份代理将变为 live 状态,下一次备份就成为其备份。当原始 live 代理恢复在线时,它无法启动故障,因为现在已经备份的代理已经有备份。

      group-name
      此 live-backup 组的名称(可选)。要形成 live-backup 组,必须使用相同的组名称和备份代理配置 live-backup 代理。如果您没有指定 group-name,备份代理可以使用任何实时代理复制。
      vote-on-replication-failure

      这个属性控制实时代理在中断复制连接时是否启动了一个称为 实时投票 的仲裁投票。已成为活跃的备份代理被视为实时代理,并可启动实时投票。

      实时投票是实时代理以确定其合作伙伴是否是中断复制连接的原因。根据投票结果,实时代理会继续运行或关闭。

    6. (可选)配置备份代理启动的仲裁投票的属性。

      <configuration>
          <core>
              ...
              <ha-policy>
                  <replication>
                      <slave>
                      ...
                          <vote-retries>12</vote-retries>
                          <vote-retry-wait>5000</vote-retry-wait>
                      ...
                      </slave>
                  </replication>
              </ha-policy>
              ...
          </core>
      </configuration>
      vote-retries
      这个属性控制备份代理重试仲裁投票的次数,以便接收备份代理启动的主要结果。
      vote-retry-wait
      此属性控制每个重试仲裁投票之间等待的时间(以毫秒为单位)。
    7. 为备份代理配置任何其他 HA 属性。

      这些额外的 HA 属性具有适用于大多数常见用例的默认值。因此,如果不需要默认行为,您只需要配置这些属性。更多信息请参阅 附录 F, 额外的复制高可用性配置元素

  3. 对集群中的每个额外的 live-backup 组重复步骤 2。

    如果集群中有六个代理,请多次重复这个过程;对每个剩余的 live-backup 组重复一次。

其他资源

14.3.4. 仅实时配置有限高可用性

通过 Live-only HA 策略,您可以在不丢失任何消息的情况下关闭集群中的代理。使用实时代理时,当实时代理安全停止时,它会将信息及事务状态复制到另一个实时代理,然后关闭。然后,客户端可以重新连接其他代理,以继续发送和接收消息。

仅实时 HA 策略仅在代理安全停止时进行处理。它不处理意外代理失败。

虽然只有实时 HA 会阻止消息丢失,但可能无法保留消息顺序。如果使用 live-only HA 配置的代理停止,则会将其消息附加到另一个代理队列的末尾。

注意

当代理准备缩减时,它会在它们断开连接前向客户端发送一条信息,并通知新代理可以处理它们的消息。但是,只有在初始代理完成缩减后,客户端才应重新连接到新代理。这样可确保在客户端重新连接时,其他代理上可以使用任何状态,如队列或事务。当客户端重新连接时,通常会重新连接设置,因此您应设置足够高的时间来处理缩减所需的时间。

这个步骤描述了如何在集群中配置每个代理来缩减。完成此步骤后,每当代理被安全停止时,它会将信息及事务状态复制到集群中的另一个代理中。

流程

  1. 打开第一个代理的 < broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 将代理配置为使用仅限实时 HA 策略。

    <configuration>
        <core>
            ...
            <ha-policy>
                <live-only>
                </live-only>
            </ha-policy>
            ...
        </core>
    </configuration>
  3. 配置一个缩减代理集群的方法。

    指定此代理应缩减的代理或代理组。

    将缩减至…​这些以下操作

    集群中的特定代理

    指定要缩减的代理的连接器。

    <live-only>
        <scale-down>
            <connectors>
                <connector-ref>broker1-connector</connector-ref>
            </connectors>
        </scale-down>
    </live-only>

    集群中的任何代理

    指定代理集群的发现组。

    <live-only>
        <scale-down>
            <discovery-group-ref discovery-group-name="my-discovery-group"/>
        </scale-down>
    </live-only>

    特定代理组中的代理

    指定代理组。

    <live-only>
        <scale-down>
            <group-name>my-group-name</group-name>
        </scale-down>
    </live-only>
  4. 对集群中的每个剩余的代理重复此步骤。

其他资源

  • 有关只使用实时缩减集群的代理集群示例,请参阅 缩减示例程序

14.3.5. 使用共存备份配置高可用性

除了配置 live-backup 组外,您还可以将备份代理与另一个实时代理位于同一个 JVM 中。在此配置中,每个实时代理配置为请求另一个实时代理,以在 JVM 中创建并启动备份代理。

图 14.4. 共存和备份代理

HA Colocated

您可以将 colocation 与共享存储或复制用作高可用性(HA)策略。新的备份代理会继承创建它的 live 代理中的配置。备份的名称设置为 colocated_backup_n,其中 n 是创建 live 代理的备份数量。

另外,备份代理会继承其连接器的配置和创建它的 live 代理中的接收器。默认情况下,端口偏移 100 应用于每个端口。例如,如果实时代理具有端口 61616 的接受器,所创建的第一个备份代理将使用端口 61716,第二个备份将使用 61816,以此类推。

日志、大型消息和分页的目录会根据您选择的 HA 策略设置。如果您选择共享存储,请求代理会通知要使用的目标代理。如果选择了复制,则目录将从创建代理继承,并附加新的备份名称。

此流程将集群中的每个代理配置为使用共享存储 HA,并请求创建备份并与集群中的另一个代理在一起。

流程

  1. 打开第一个代理的 < broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 将代理配置为使用 HA 策略和 colocation。

    在本例中,代理被配置为使用共享存储 HA 和 colocation。

    <configuration>
        <core>
            ...
            <ha-policy>
                <shared-store>
                    <colocated>
                        <request-backup>true</request-backup>
                        <max-backups>1</max-backups>
                        <backup-request-retries>-1</backup-request-retries>
                        <backup-request-retry-interval>5000</backup-request-retry-interval/>
                        <backup-port-offset>150</backup-port-offset>
                        <excludes>
                            <connector-ref>remote-connector</connector-ref>
                        </excludes>
                        <master>
                            <failover-on-shutdown>true</failover-on-shutdown>
                        </master>
                        <slave>
                            <failover-on-shutdown>true</failover-on-shutdown>
                            <allow-failback>true</allow-failback>
                            <restart-backup>true</restart-backup>
                        </slave>
                    </colocated>
                </shared-store>
            </ha-policy>
            ...
        </core>
    </configuration>
    request-backup
    通过将此属性设置为 true,此代理将请求由集群中的另一个实时代理创建备份代理。
    max-backups
    此代理可以创建的备份代理数量。如果将此属性设置为 0,则此代理不接受来自集群中其他代理的备份请求。
    backup-request-retries
    此代理应尝试请求创建备份代理的次数。默认值为 -1,这表示无限尝试。
    backup-request-retry-interval
    在重试请求以创建备份代理前代理应等待的时间(毫秒)。默认值为 5000 或 5 秒。
    backup-port-offset
    用于新备份代理的端口偏移和连接器。如果此代理收到一个请求来为集群中的另一个代理创建备份,它将使用这个数量来创建带有端口偏移的备份代理。默认值为 100
    excludes (可选)
    从备份端口偏移中排除连接器。如果您已经为应从备份端口偏移中排除的外部代理配置了任何连接器,请为每个连接器添加一个 &lt ;connector-ref >。
    master
    此代理的共享存储或复制故障切换配置。
    slave
    此代理备份的共享存储或复制故障转移配置。
  3. 对集群中的每个剩余的代理重复此步骤。

其他资源

  • 有关使用共存备份的代理集群示例,请参阅 HA 示例程序

14.3.6. 将客户端配置为故障切换

在代理集群中配置高可用性后,您可以将客户端配置为故障切换。客户端故障转移可确保代理出现故障,连接到它的客户端可以在最小停机时间的情况下重新连接到集群中的其他代理。

注意

如果出现临时网络问题,AMQ Broker 会自动重新将连接重新连接到同一代理。这和故障转移类似,但客户端会重新连接到同一代理。

您可以配置两种类型的客户端故障切换:

自动客户端故障切换
客户端在第一次连接时接收代理集群的信息。如果连接的代理失败,客户端会自动重新连接到代理的备份,备份代理会在故障切换前重新创建所有存在于会话和使用者。
应用程序级别的客户端故障转移
作为自动客户端故障切换的替代选择,您可以在故障处理程序中使用您自己的自定义重新连接逻辑来编写客户端应用程序。

流程

14.4. 启用消息重新分发

如果您的代理集群配置了 消息-load-balancing 设置为 ON_DEMANDOFF_WITH_REDISTRIBUTION,则可以配置 消息 重新分配以防止在队列中没有消费者使用消息的消息"stuck"。

这部分包含有关以下内容的信息:

14.4.1. 了解消息重新分发

代理集群使用负载均衡来在集群中分发消息负载。当在集群连接中配置负载均衡时,您可以使用 以下消息-load-balancing 设置启用 redistribution:

  • ON_DEMAND - 启用负载均衡并允许重新分发
  • OFF_WITH_REDISTRIBUTION - 禁用负载均衡,但允许重新分发

在这两种情况下,代理仅将信息转发给具有匹配消费者的其他代理。这个行为可确保消息不会移到没有消费者使用消息的队列。但是,如果在消息转发到代理后连接到队列后,这些消息会在队列中变为"stuck"且不会被使用。此问题有时被称为 星号

消息重新分发通过自动重新分发消息从没有消费者到集群中有匹配使用者的代理的队列重新分发。

使用 OFF_WITH_REDISTRIBUTION 时,代理仅在没有活跃本地消费者的情况下将消息转发到匹配消费者的其他代理,允许您在提供消费者不可用时优先考虑代理。

消息重新分发支持使用过滤器(也称为 选择器),即当消息与可用本地消费者的选择器不匹配时重新分发。

其他资源

14.4.2. 配置消息重新分发

此步骤演示了如何配置消息重新使用负载均衡。如果您希望在没有负载均衡的情况下重新分配消息,将 &lt ;message-load-balancing& gt; 设置为 OFF_WITH_REDISTRIBUTION

流程

  1. 打开 & lt;broker_instance_dir&gt; /etc/broker.xml 配置文件。
  2. 在 & lt;cluster-connection&gt; 元素中,验证 <message-load-balancing& gt; 是否已设置为 ON_DEMAND

    <configuration>
        <core>
            ...
            <cluster-connections>
                <cluster-connection name="my-cluster">
                    ...
                    <message-load-balancing>ON_DEMAND</message-load-balancing>
                    ...
                </cluster-connection>
            </cluster-connections>
        </core>
    </configuration>
  3. 在 & lt;address-settings > 元素内,为队列或一组队列设置重新分发延迟。

    在这个示例中,在最后一个消费者接近后,负载均衡到 my.queue 的消息将被重新分配 5000 毫秒。

    <configuration>
        <core>
            ...
            <address-settings>
                <address-setting match="my.queue">
                    <redistribution-delay>5000</redistribution-delay>
                </address-setting>
            </address-settings>
            ...
        </core>
    </configuration>
    address-setting
    match 属性设置为您要重新分发消息的队列的名称。您可以使用代理通配符语法来指定一系列队列。更多信息请参阅 第 4.2 节 “将地址设置应用到一组地址”
    redistribution-delay
    代理在将信息重新分发至集群中其他代理之前,代理在最终消费者关闭后应等待的时间(以毫秒为单位)。如果将其设置为 0, 则会立即重新分发信息。但是,您应该在重新分发前设置延迟 - 这对于消费者而言很常见,但要在同一队列上快速创建另一个对象。
  4. 对集群中的每个额外代理重复此步骤。

其他资源

14.5. 配置集群消息分组

消息分组可让客户端发送特定类型的消息组,以便按同一消费者按顺序处理。通过向集群中的每个代理添加分组处理程序,您可以确保客户端可以向集群中的任何代理发送分组消息,并仍能以同一消费者使用正确顺序使用这些消息。

注意

集群提供并行性,使您能够水平扩展,而分组技术则为特定消费者直接分组的消息。

红帽建议您使用集群分组,并避免将集群和分组一起使用。

有两种分组处理程序:local handlersremote handlers。它们可让代理集群将特定组中的所有消息路由到适当的队列,以便预期消费者以正确顺序使用它们。

先决条件

  • 集群中每个代理上应该至少有一个消费者。

    当消息固定到队列中的消费者时,具有相同组 ID 的所有消息都将路由到该队列。如果删除了使用者,队列仍会在没有消费者的情况下收到消息。

流程

  1. 在集群中的一个代理上配置本地处理器。

    如果您使用高可用性,则应该是 master 代理。

    1. 打开代理的 < broker_instance_dir&gt; /etc/broker.xml 配置文件。
    2. 在 & lt;core > 元素中添加本地处理器:

      本地处理程序充当远程处理程序的仲裁符。它存储路由信息并将其与其他代理通信。

      <configuration>
          <core>
              ...
              <grouping-handler name="my-grouping-handler">
                  <type>LOCAL</type>
                  <timeout>10000</timeout>
              </grouping-handler>
              ...
          </core>
      </configuration>
      grouping-handler
      使用 name 属性指定分组处理程序的唯一名称。
      type
      把它设置为 LOCAL
      timeout

      等待(以毫秒为单位)等待多长时间以便决定路由邮件的位置。默认值为 5000 毫秒。如果在做出路由决策前达到超时,则引发异常,以确保严格的消息排序。

      当代理收到带有组 ID 的消息时,它会将路由引入到消费者所附加的队列。如果路由被集群中的其他代理中的分组处理程序接受,则建立路由:集群中所有代理的所有代理都会将带有此组 ID 的消息转发到该队列。如果代理的路由提议被拒绝,那么它将给出一个替代路由,重复这个过程,直到接受路由为止。

  2. 如果您使用高可用性,请将本地处理器配置复制到主代理的从代理中。

    将本地处理器配置复制到从属代理可防止本地处理程序的单点故障。

  3. 在集群的每个剩余代理中配置远程处理器。

    1. 打开代理的 < broker_instance_dir&gt; /etc/broker.xml 配置文件。
    2. 在 & lt;core > 元素中添加远程处理器:

      <configuration>
          <core>
              ...
              <grouping-handler name="my-grouping-handler">
                  <type>REMOTE</type>
                  <timeout>5000</timeout>
              </grouping-handler>
              ...
          </core>
      </configuration>
      grouping-handler
      使用 name 属性指定分组处理程序的唯一名称。
      type
      将其设置为 REMOTE
      timeout
      等待(以毫秒为单位)等待多长时间以便决定路由邮件的位置。默认值为 5000 毫秒。将此值设置为本地处理程序的值至少一半。

其他资源

14.6. 将客户端连接到代理集群

您可以使用 AMQ JMS 客户端连接到集群。通过使用 JMS,您可以将消息传递客户端配置为动态或静态发现代理列表。您还可以配置客户端负载均衡,以分发从集群间连接创建的客户端会话。

流程

14.7. 分区客户端连接

分区客户端连接涉及在客户端启动连接时,各个客户端到同一代理的路由连接。

分区客户端连接的两个用例是:

  • 对持久订阅进行分区,以确保订阅者始终连接到位于 durable subscriber 队列所在代理。
  • 通过吸引客户到源自数据的数据(也称为数据信息)来最大程度地减少将数据移至移至数据的需求。

持久化订阅

持久化订阅以代理上的队列形式表示,并在意外的订阅者第一次连接到代理时创建。这个队列保留在代理中,并接收信息,直到客户端取消订阅。因此,您希望客户端会重复连接到同一代理,以使用订阅者队列中的消息。

要为持久订阅队列对客户端进行分区,您可以在客户端连接中过滤客户端 ID。

数据 getvity

如果您在没有考虑数据的情况下扩展代理数量而不考虑数据,则由于需要在代理间移动消息,一些性能优势将会丢失。为了支持日期 getvity,您应该对客户端连接进行分区,以便客户端消费者连接生成所需信息所需的代理。

要对客户端连接进行分区以支持数据状态,您可以过滤以下客户端连接的属性:

  • 分配给连接用户(ROLE_NAME)的角色。
  • 用户的用户名(USER_NAME)
  • 客户端的主机名(SNI_HOST)
  • 客户端的 IP 地址(SOURCE_IP)

14.7.1. 对客户端连接进行分区以支持持久订阅

要为持久订阅分区客户端,您可以使用一致的哈希算法或正则表达式在传入连接中过滤客户端 ID。

先决条件

客户端经过配置,以便它们可以连接到集群中的所有代理,例如使用负载均衡器,或者具有在连接 URL 中配置的所有代理实例。如果代理因为客户端详情与该代理的分区配置不匹配,客户端必须能够连接到集群中的其他代理,以查找接受该代理的连接。

14.7.1.1. 使用一致的哈希算法过滤客户端 ID

您可以在一个集群中配置每个代理,以使用一致的哈希算法来在每个客户端连接中对客户端 ID 进行哈希处理。在代理对客户端 ID 哈希后,它会在散列值上执行 modulo 操作,返回整数值,用于标识客户端连接的目标代理。代理将返回的整数值与代理中配置的唯一值进行比较。如果存在匹配项,代理会接受连接。如果值不匹配,代理会拒绝连接。此过程会在集群中的每个代理上重复,直到找到匹配项并且代理接受连接。

流程

  1. 为第一个代理打开 < broker_instance_dir> /etc/broker.xml 配置文件。
  2. 创建 connection-routers 元素,并使用一致的哈希算法创建连接 路由 以过滤客户端 ID。例如:

    <configuration>
       <core>
          ...
          <connection-routers>
             <connection-route name=”consistent-hash-routing”>
                <key>CLIENT_ID</target-key>
                <local-target-filter>NULL|0</local-target-filter>
                <policy name="CONSISTENT_HASH_MODULO">
                   <property key="modulo" value="<number_of_brokers_in_cluster>">
                   </property>
                </policy>
             </connection-route>
          </connection-routers>
          ...
       </core>
    </configuration>
    connection-route
    对于 connection-route 名称,请为这个连接路由配置指定标识字符串。您必须将此名称添加到每个代理接受器中,您要将一致的散列过滤器应用到其中。
    key
    要将过滤器应用到的键类型。要过滤客户端 ID,在 key 字段中指定 CLIENT_ID
    local-target-filter
    代理与 modulo 操作返回的整数值进行比较的值,以确定是否有匹配项并且代理可以接受连接。示例中的 NULL|0 值为没有客户端 ID(NULL)的连接提供了匹配的连接,其中 modulo 操作返回的数量为 0
    policy

    接受 modulo 属性键,它在散列客户端 ID 上执行 modulo 操作来识别目标代理。modulo 属性键的值必须等于集群中的代理数量。

    重要

    策略名称 必须是 CONSISTENT_HASH_MODULO

  3. 为第二个代理打开 < broker_instance_dir> /etc/broker.xml 配置文件。
  4. 创建 connection-routers 元素,并使用一致的哈希算法创建用于过滤客户端 ID 的连接路由

    在以下示例中,local-target-filterNULL|1 为没有客户端 ID(NULL)的连接提供了匹配的连接,其中 modulo 操作返回的值为 1

    <configuration>
       <core>
          ...
          <connection-routers>
             <connection-route name=”consistent-hash-routing”>
                <key>CLIENT_ID</target-key>
                <local-target-filter>NULL|1</local-target-filter>
                <policy name="CONSISTENT_HASH_MODULO">
                   <property key="modulo" value="<number_of_brokers_in_cluster>">
                   </property>
                </policy>
             </connection-route>
          </connection-routers>
          ...
       </core>
    </configuration>
  5. 重复此流程,为集群中的每个额外代理创建一致的哈希过滤器。
14.7.1.2. 使用正则表达式过滤客户端 ID

您可以通过将代理配置为将正则表达式过滤器应用到客户端连接中客户端 ID 的一部分来对客户端连接进行分区。只有在正则表达式过滤器的结果与为代理配置的本地目标过滤器匹配时,代理才接受连接。如果没有找到匹配项,代理会拒绝连接。此过程会在集群中的每个代理上重复,直到找到匹配项并且代理接受连接。

先决条件

  • 每个客户端 ID 中的常用字符串,可以按正则表达式进行过滤。

流程

  1. 为第一个代理打开 < broker_instance_dir> /etc/broker.xml 配置文件。
  2. 创建 connection-routers 元素并创建一个 connection-route 来过滤客户端 ID 的一部分。例如:

    <configuration>
        <core>
            ...
            <connection-routers>
                <connection-route name=”regex-routing”>
                    <key>CLIENT_ID</target-key>
                    <key-filter>^.{3}</key-filter>
                    <local-target-filter>NULL|FOO</local-target-filter>
                </connection-route>
        </connection-routers>
            ...
        </core>
    </configuration>
    connection-route
    对于 connection-route 名称,请为此路由配置指定标识字符串。您必须将此名称添加到要应用正则表达式过滤器的每个代理接受器中。
    key
    要将过滤器应用到的键。要过滤客户端 ID,在 key 字段中指定 CLIENT_ID
    key-filter

    将正则表达式应用到的客户端 ID 字符串中用于提取键值。在上面的第一个代理示例中,代理提取一个键值,它是客户端 ID 的前 3 个字符。例如,如果客户端 ID 字符串是 FOO100.consumer,则代理提取一个键值 FOO。代理提取键值后,它会将其与 local-target-filter 的值进行比较。

    如果传入的连接没有客户端 ID,或者代理无法使用为 key-filter 指定的正则表达式提取键值,则键值设置为 NULL。

    local-target-filter
    代理与键值比较的值,以确定是否有匹配项并且代理可以接受连接。上面的第一个代理示例所示的 NULL|FOO 值匹配,与没有客户端 ID(NULL)或在客户端 ID 中具有 3 个字符前缀 FOO 的连接匹配。
  3. 为第二个代理打开 < broker_instance_dir> /etc/broker.xml 配置文件。
  4. 创建 connection-routers 元素,并创建 连接路由,以根据客户端 ID 的一部分过滤连接。

    在以下过滤器示例中,代理使用正则表达式提取一个键值,它是客户端 ID 的前 3 个字符。代理将 NULLBAR 的值与键值进行比较,以确定是否有匹配项和代理可以接受连接。

    <configuration>
        <core>
            ...
            <connection-routers>
                <connection-route name=”regex-routing”>
                    <key>CLIENT_ID</target-key>
                    <key-filter>^.{3}</key-filter>
                    <local-target-filter>NULL|BAR</local-target-filter>
                </connection-route>
            </connection-routers>
            ...
        </core>
    </configuration>
  5. 重复此步骤,并为集群中的每个附加代理创建适当的连接路由过滤器。

14.7.2. 对客户端连接进行分区以支持数据状态

为了支持日期 getvity,您可以对客户端连接进行分区,以便客户端用户连接到生成了它们使用的消息的代理。例如,如果您有一组由制作者和消费者应用程序使用的地址,您可以在特定的代理上配置地址。然后,您可以为使用这些地址的生产者和消费者对客户端连接进行分区,以便它们只能连接到该代理。

您可以基于分配给连接用户的角色、用户的用户名或客户端的主机名或 IP 地址来对客户端连接进行分区。本节演示了如何通过过滤分配给客户端用户的用户角色来对客户端连接进行分区。如果需要客户端与代理进行身份验证,您可以向客户端用户分配角色,并过滤连接,以便只有与角色条件匹配的用户才能连接到代理。

先决条件

  • 客户端经过配置,以便它们可以连接到集群中的所有代理,例如使用负载均衡器,或者具有在连接 URL 中配置的所有代理实例。如果代理拒绝连接,因为客户端与为该代理配置的分区过滤器标准不匹配,客户端必须能够连接到集群中的其他代理,以查找接受该代理的连接的代理。

流程

  1. 为第一个代理打开 < broker_instance_dir> /etc/artemis-roles.properties 文件。添加 broker1users 角色,并将用户添加到角色中。
  2. 为第一个代理打开 < broker_instance_dir> /etc/broker.xml 配置文件。
  3. 创建 connection-routers 元素并创建一个 connection-route,以根据分配给用户的角色过滤连接。例如:

    <configuration>
        <core>
            ...
            <connection-routers>
                <connection-route name=”role-based-routing”>
                    <key>ROLE_NAME</target-key>
                    <key-filter>broker1users</key-filter>
                    <local-target-filter>broker1users</local-target-filter>
                </connection-route>
            </connection-routers>
            ...
        </core>
    </configuration>
    connection-route
    对于 connection-route 名称,请为此路由配置指定标识字符串。您必须将此名称添加到要应用角色过滤器的每个代理接受器中。
    key
    要将过滤器应用到的键。要配置基于角色的过滤,在 key 字段中指定 ROLE_NAME
    key-filter
    代理用来过滤用户的角色并提取键值的字符串或正则表达式。如果代理找到匹配的角色,它会将键值设置为该角色。如果找不到匹配的角色,代理会将键值设置为 NULL。在上例中,代理将 broker1users 的过滤器应用到客户端用户的角色。代理提取键值后,它会将其与 local-target-filter 的值进行比较。
    local-target-filter
    代理与键值比较的值,以确定是否有匹配项并且代理可以接受连接。在示例中,代理将 broker1users 值与键值进行比较。它有一个匹配项,这意味着用户具有 broker1users 角色,代理接受连接。
  4. 重复此步骤,并在过滤器中指定适当的角色来在集群中的其他代理上对客户端进行分区。

14.7.3. 为接收器添加连接路由

在代理中配置连接路由后,您必须将路由添加到一个或多个代理的接收器中分区客户端连接。将连接路由添加到接受器后,代理会将连接路由中配置的过滤器应用到接受者接收的连接。

流程

  1. 为第一个代理打开 < broker_instance_dir> /etc/broker.xml 配置文件。
  2. 对于您要启用分区的每个接受者,附加 路由器 密钥并指定 connection-route 名称。在以下示例中,将具有 consistent-hash-routingconnection-route name 添加到 artemis acceptor 中。

    <configuration>
        <core>
            ...
            <acceptors>
            ...
            <!-- Acceptor for every supported protocol -->
            <acceptor name="artemis">tcp://0.0.0.0:61616?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=CORE,AMQP,STOMP,HORNETQ,MQTT,OPENWIRE;useEpoll=true;amqpCredits=1000;amqpLowCredits=300;router="consistent-hash-routing" </acceptor>
          </acceptors>
            ...
        </core>
    </configuration>
  3. 重复此流程,为集群中的每个代理指定适当的连接路由过滤器。

第 15 章 使用 Ceph 配置多站点、容错的消息传递系统

大型企业消息传递系统通常具有分散的代理集群,位于地理分布的数据中心上。如果数据中心中断,系统管理员可能需要保留现有的消息传递数据,并确保客户端应用程序能够继续生成和使用消息。您可以使用特定的代理拓扑和 Red Hat Ceph Storage(一种软件定义的存储平台),在数据中心停机期间确保消息传递系统的连续性。这种类型的解决方案称为 多站点容错架构

注意

如果您只需要 AMQP 协议的支持,请考虑 第 16 章 使用代理连接配置多站点、容错的消息传递系统

以下小节解释了如何使用 Red Hat Ceph Storage 保护消息传递系统不受数据中心故障的影响:

注意

多站点容错并不取代 数据中心内的 高可用性(HA)代理冗余。基于 live-backup 组的代理冗余提供了对单个集群中的单个代理故障进行自动保护。相比之下,多站点容错可以保护大规模数据中心故障。

注意

要使用 Red Hat Ceph Storage 以确保消息传递系统的连续性,您必须将代理配置为使用共享存储高可用性(HA)策略。您不能将代理配置为使用复制 HA 策略。有关这些策略的更多信息,请参阅 实施高可用性

15.1. Red Hat Ceph Storage 集群如何工作

Red Hat Ceph Storage 是一个集群对象存储系统。Red Hat Ceph Storage 使用对象的数据分片和基于策略的复制来保证数据完整性和系统可用性。

Red Hat Ceph Storage 使用名为 CRUSH(可扩展哈希下的受控复制)的算法,以确定如何通过自动计算数据存储位置存储和检索数据。您可以配置名为 CRUSH map 的 Ceph 项,它详细说明集群拓扑,并且指定如何在存储集群之间复制数据。

CRUSH map 包含对象存储设备(OSD)的列表、将设备聚合到故障域层次结构的"bucket"列表,以及告知 CRUSH 如何在 Ceph 集群池中复制数据的规则。

通过反映安装的底层物理组织,libvirt 映射可以建模,从而解决了关联设备故障的潜在源,如物理不可变、共享电源源和共享网络。通过将此信息编码到集群映射中,libvirt 可在不同的故障域(如数据中心)之间分离对象副本,同时仍然维护存储集群中的伪随机数据分布。这有助于防止数据丢失并让集群以降级状态运行。

Red Hat Ceph Storage 集群需要有多个节点(物理或虚拟)。集群必须包括以下类型的节点:

监控节点

每个 monitor(MON)节点运行 monitor 守护进程(ceph-mon),它维护 cluster map 的 master 副本。集群映射包含集群拓扑。连接到 Ceph 集群的客户端从监控器检索 cluster map 的当前副本,这使客户端可以从集群读取和写入数据。

重要

Red Hat Ceph Storage 集群可以使用一个监控器节点运行;但是,为了确保生产集群中的高可用性,红帽仅支持至少含有三个 monitor 节点的部署。最少三个 monitor 节点意味着,如果一个 monitor 出现故障或不可用,则集群中剩余的 monitor 节点存在仲裁,以选择新的领导。

Manager 节点

每个管理器(MGR)节点运行 Ceph 管理器守护进程(ceph-mgr),它负责跟踪运行时指标和 Ceph 集群的当前状态,包括存储利用率、当前性能指标和系统负载。通常,管理器节点与 monitor 节点处于共同位置(即位于同一主机上)。

Object Storage Device 节点

每个对象存储设备(OSD)节点运行 Ceph OSD 守护进程(ceph-osd),它与附加到节点的逻辑卷交互。Ceph 在 OSD 节点上存储数据。Ceph 可以在非常少的 OSD 节点时运行(默认为三个),但生产集群在某一存储集群中具有 50 个 OSD 以更优的性能。通过存储集群中有多个 OSD,系统管理员可以在 CRUSH map 内定义隔离故障域。

元数据服务器节点

每个元数据服务器(MDS)节点运行 MDS 守护进程(ceph-mds),后者管理与 Ceph 文件系统(CephFS)中存储的文件相关的元数据。MDS 守护进程也协调对共享集群的访问。

其他资源

有关 Red Hat Ceph Storage 的更多信息,请参阅什么是 Red Hat Ceph Storage?

15.2. 安装 Red Hat Ceph Storage

AMQ Broker 多站点、容错架构使用 Red Hat Ceph Storage 3。通过跨数据中心复制数据,Red Hat Ceph Storage 集群可以有效地创建可用于不同数据中心的代理的共享存储。您可以将代理配置为使用共享存储高可用性(HA)策略,并将消息传递数据存储在 Red Hat Ceph Storage 集群中。

用于生产环境的 Red Hat Ceph Storage 集群应至少具有:

  • 三个 monitor(MON)节点
  • 三个管理器(MGR)节点
  • 三个对象存储设备(OSD)节点,包含多个 OSD 守护进程
  • 三个元数据服务器(MDS)节点
重要

您可以在相同或独立的物理或虚拟机中运行 OSD、MON、MGR 和 MDS 节点。但是,为了确保 Red Hat Ceph Storage 集群中的容错,最好在不同数据中心之间分布这些类型的节点。特别是,您必须确保当单个数据中心停机时,您的存储集群仍然有两个可用的 MON 节点。因此,如果您在集群中有三个 MON 节点,则每个节点必须在单独的数据中心的独立主机上运行。不要在一个数据中心中运行两个 MON 节点,因为此数据中心失败会使您的存储集群仅保留一个剩余的 MON 节点。在这种情况下,存储集群无法再操作。

本节的链接流程介绍了如何安装包括 MON、MGR、OSD 和 MDS 节点的 Red Hat Ceph Storage 3 集群。

先决条件

流程

15.3. 配置 Red Hat Ceph Storage 集群

本例步骤演示了如何为容错配置 Red Hat Ceph 存储集群。您可以创建 CRUSH 存储桶,将对象存储设备(OSD)节点聚合到反映您的实际物理安装的数据中心。此外,您还可创建一个规则,告知 CRUSH 如何在存储池中复制数据。这些步骤会更新 Ceph 安装创建的默认 CRUSH map。

先决条件

  • 已安装 Red Hat Ceph Storage 集群。有关更多信息,请参阅安装 Red Hat Ceph Storage
  • 您应该了解 Red Hat Ceph Storage 如何使用放置组(PG)在池中组织大量数据对象,以及如何计算池中要使用的 PG 数量。如需更多信息,请参阅 放置组(PG)
  • 您应该了解如何在池中设置对象副本数。如需更多信息,请参阅设置对象副本的数量

流程

  1. 创建 CRUSH bucket 以整理 OSD 节点。bucket 是 OSD 的列表,基于数据中心等物理位置。在 Ceph 中,这些物理位置被称为 故障域

    ceph osd crush add-bucket dc1 datacenter
    ceph osd crush add-bucket dc2 datacenter
  2. 将 OSD 节点的主机机器移到您创建的数据中心 CRUSH bucket 中。将主机名 host1-host4 替换为您的主机的名称。

    ceph osd crush move host1 datacenter=dc1
    ceph osd crush move host2 datacenter=dc1
    ceph osd crush move host3 datacenter=dc2
    ceph osd crush move host4 datacenter=dc2
  3. 确保您创建的 CRUSH 存储桶 是默认 CRUSH 树的一部分。

    ceph osd crush move dc1 root=default
    ceph osd crush move dc2 root=default
  4. 创建一条规则来映射数据中心中的存储对象副本。这有助于防止数据丢失并让集群在单一数据中心中断时继续运行。

    创建规则的命令使用以下语法: ceph osd crush rule create-replicated <rule-name> <root> <failure-domain> <class>.下面是一个示例。

    ceph osd crush rule create-replicated multi-dc default datacenter hdd
    注意

    在前面的命令中,如果存储集群使用固态驱动器(SSD),请指定 ssd 而不是 hdd (硬盘)。

  5. 将您的 Ceph 数据和元数据池配置为使用您创建的规则。最初,这可能导致数据回填到由 CRUSH 算法决定的存储目的地。

    ceph osd pool set cephfs_data crush_rule multi-dc
    ceph osd pool set cephfs_metadata crush_rule multi-dc
  6. 为您的元数据和数据池指定放置组(PG)和放置组的数量。PGP 值应该等于 PG 值。

    ceph osd pool set cephfs_metadata pg_num 128
    ceph osd pool set cephfs_metadata pgp_num 128
    
    ceph osd pool set cephfs_data pg_num 128
    ceph osd pool set cephfs_data pgp_num 128
  7. 指定您的数据和元数据池使用的副本数。

    ceph osd pool set cephfs_data min_size 1
    ceph osd pool set cephfs_metadata min_size 1
    
    ceph osd pool set cephfs_data size 2
    ceph osd pool set cephfs_metadata size 2

下图显示了由上一示例步骤创建的 Red Hat Ceph Storage 集群。存储群集将 OSD 整理到与数据中心对应的 CRUSH bucket 中。

代理灾难恢复 1

下图显示了第一个数据中心的可能布局,包括您的代理服务器。具体来说,数据中心主机:

  • 两个实时备份代理对的服务器
  • 您分配给前面流程中第一个数据中心的 OSD 节点
  • 单个元数据服务器、监控和管理器节点。Monitor 和 Manager 节点通常位于同一个机器上。
代理灾难恢复 2
重要

您可以在相同或独立的物理或虚拟机中运行 OSD、MON、MGR 和 MDS 节点。但是,为了确保 Red Hat Ceph Storage 集群中的容错,最好在不同数据中心之间分布这些类型的节点。特别是,您必须确保当单个数据中心停机时,存储集群仍然有两个可用的 MON 节点。因此,如果您在集群中有三个 MON 节点,则每个节点必须在单独的数据中心的独立主机上运行。

下图显示了一个完整的示例拓扑。为确保存储集群中的容错、MON、MGR 和 MDS 节点分布在三个独立的数据中心。

代理灾难恢复 10
注意

在与代理服务器相同的数据中心中为某些 OSD 节点查找主机机器并不意味着您将消息传递数据存储在这些特定的 OSD 节点上。您可以配置代理将消息传递数据存储在 Ceph 文件系统的指定目录中。然后,集群中的存储服务器节点决定如何在数据中心中的所有可用 OSD 中分发存储数据并在数据中心间处理此数据的复制。以下小节显示如何配置代理以在 Ceph 文件系统中存储消息传递数据。

下图演示了在具有代理服务器的两个数据中心之间复制数据。

代理灾难恢复 3

其他资源

有关以下内容的更多信息:

  • 为 Red Hat Ceph Storage 集群管理 CRUSH,请参阅