配置 AMQ Broker

Red Hat AMQ 2020.Q4

用于与 AMQ Broker 7.8 一起使用

摘要

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

第 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 包含以下功能的默认设置:

  • 消息持久性
  • 接收器
  • 安全性
  • 消息地址

默认消息持久性设置

默认情况下,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>

默认接受器设置

代理使用接收器配置元素来侦听传入客户端连接,以定义客户端可用于进行连接的端口和协议。默认情况下,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 密钥存储和信任存储,以建立新证书,而不会对现有客户端产生任何影响。连接的客户端(即使具有旧或不同证书的客户端)可以继续发送和接收消息。

  • rts

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

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

步骤

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

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

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

1.4. 合并代理配置文件

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

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

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

步骤

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

    每个 XML 文件只能包括 broker.xml 的单个部分(例如,地址或地址设置,但不能同时包含两者)。顶级元素还必须定义元素命名空间(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. 为每个应该使用常见配置设置的代理打开 <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 验证程序。这个示例使用 xmllint 根据 artemis-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指定的值 ),不会自动 检测 broker.xml 配置文件中包含的 配置文件的更改。例如,如果 broker.xml 包含 my-address-settings.xml,并且您对 my-address-settings.xml 进行了配置更改,则代理不会自动检测 my-address-settings.xml 中的更改并重新载入配置。

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

$ touch -m <broker-instance-dir>/etc/broker.xml

1.5. 文档规范

本文档对 sudo 命令和文件路径使用以下惯例。

sudo 命令

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

有关使用 sudo 的更多信息,请参阅 sudo 命令

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

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

第 2 章 网络连接:acceptors 和 Connectors

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

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

网络连接配置中的 URI 决定其类型。例如,在 URI 中使用 vm 将创建一个 In-VM 连接。在以下示例中,请注意接受者的 URI vm 开头。

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

在 URI 中使用 tcp,也可以创建网络连接。

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

本章首先讨论专用于网络连接、验收器和连接器的两个配置元素。接下来,会解释 TCP、HTTP 和 SSL/TLS 网络连接以及 In-VM 连接的配置步骤。

2.1. 关于接受者

在讨论 AMQ Broker 中的网络连接时,最重要的概念之一是接受者。接收器定义连接到代理的方式。以下是在配置文件 BROKER_INSTANCE_DIR/etc/broker.xml 中找到的接受人员的典型配置。

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

请注意,每个 接受 者都在接受者元素内分组。对于每个服务器可以列出的接受者数量,没有上限。

配置 Acceptor

您可以通过将键值对附加到为接受或 定义的 URI 的查询字符串来配置接收器。 使用分号(';')来分隔多个键值对,如下例中所示。它通过在 URI 的末尾添加多个键值对来为 SSL/TLS 配置接受器,从 sslEnabled=true 开始。

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

有关 连接器 配置参数的详细信息,请参阅 Acceptor 和 Connector Configuration Parameters

2.2. 关于连接器

接收器定义服务器如何接受连接,而客户端则使用 连接器 来定义它们如何连接到服务器。

以下是 BROKER_INSTANCE_DIR/etc/broker.xml 配置文件中定义的典型 连接器

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

请注意,连接器在 连接器 元素中定义。对每台服务器的连接器数量没有上限。

虽然客户端使用连接器,但它们的配置与接收器一样。为什么会有一些重要原因:

  • 服务器本身可以充当客户端,因此需要了解如何连接到其他服务器。例如,当一个服务器桥接到另一服务器时,或者当服务器在集群中某一部分时。
  • JMS 客户端通常使用服务器来查找连接工厂实例。在这些情况下,JNDI 需要知道用于创建客户端连接的连接工厂的详细信息。执行 JNDI 查找时,会向客户端提供信息。如需更多信息,请参阅在客户端 Side 上配置连接

配置连接器

与接收器一样,连接器将其配置附加到其 URI 的查询字符串中。下面是一个 连接器 示例,其 tcpNoDelay 参数设置为 false,这会关闭此连接的 Nagle 的算法。

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

有关 连接器 配置参数的详细信息,请参阅 Acceptor 和 Connector Configuration Parameters

2.3. 配置 TCP 连接

AMQ Broker 使用 Netty 提供基本、未加密的、基于 TCP 的连接,该连接可以配置为使用阻塞 Java IO 或更新的非阻塞 Java NIO。Java NIO 是拥有许多并发连接更好的可扩展性。但是,使用旧的 IO 有时,如果您不担心支持成千上万的并发连接,则与 NIO 相比可以提供更好的延迟。

如果您在不可信网络上运行连接,请记住 TCP 网络连接是未加密的。如果加密是优先级,您可能需要考虑使用 SSL 或 HTTPS 配置来加密通过此连接发送的消息。详情请参考 第 5.1 节 “保护连接”。使用 TCP 连接时,所有连接都会从客户端一端启动。换句话说,服务器不会启动任何与客户端的连接,这适用于强制从一个方向启动连接的防火墙策略。

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

步骤

  1. 打开配置文件 BROKER_INSTANCE_DIR/etc/broker.xml
  2. 添加或修改连接,使其包含使用 tcp 作为协议的 URI。确保同时包含 IP 或主机名和端口。

在以下示例中,接受 被配置为 TCP 连接。使用这个接收器配置的代理将接受客户端向 IP 10.10.10.1 和端口 61617 进行 TCP 连接。

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

您可以将连接器配置为以大体方式使用 TCP。

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

在使 TCP 连接指定 IP 和端口 10.10.10.2:61617 时,上面的 连接器 将被客户端引用,甚至代理本身。

有关 TCP 连接的可用配置参数的详情,请参阅 Acceptor 和 Connector Configuration Parameters。大多数参数都可用于接收器或连接器,但某些参数只适用于接收器。

2.4. 配置 HTTP 连接

HTTP 连接隧道数据包通过 HTTP 协议进行,在防火墙只允许 HTTP 流量的情况下非常有用。通过单一端口支持,AMQ Broker 会自动检测是否使用 HTTP,因此为 HTTP 配置网络连接与为 TCP 配置连接相同。有关如何使用 HTTP 的完整工作示例,请参阅 http-transport 示例,它位于 INSTALL_DIR/examples/features/standard/ 下。

步骤

  1. 打开配置文件 BROKER_INSTANCE_DIR/etc/broker.xml
  2. 添加或修改连接,使其包含使用 tcp 作为协议的 URI。确保同时包含 IP 或主机名以及端口

在以下示例中,代理将接受来自从客户端连接到 IP 地址 10.10.10.1 的端口 80 的 HTTP 通信。另外,代理还会自动检测 HTTP 协议正在使用,并将相应地与客户端通信。

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

为 HTTP 配置连接器再次与 TCP 的配置方式相同。

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

使用上述示例中的配置,代理将在 IP 地址 10.10.10.2 处创建到端口 80 的出站 HTTP 连接。

HTTP 连接使用与 TCP 相同的配置参数,但它也有自己的一些。有关 HTTP 相关的和其他配置参数的详情,请参阅 Acceptor 和 Connector Configuration Parameters

2.5. 配置 SSL/TLS 连接

您还可以将连接配置为使用 SSL/TLS。详情请参考 第 5.1 节 “保护连接”

2.6. 配置 In-VM 连接

当多个代理位于同一虚拟机上时,可以使用 In-VM 连接,作为高可用性解决方案的一部分。在与服务器相同的 JVM 中运行的本地客户端还可使用 in-VM 连接。对于 in-VM 连接,URI 的授权部分定义了唯一的服务器 ID。实际上,不需要 URI 的其他部分。

步骤

  1. 打开配置文件 BROKER_INSTANCE_DIR/etc/broker.xml
  2. 添加或修改连接,使其包含使用 vm 作为协议的 URI。
<acceptors>
  <acceptor name="in-vm-acceptor">vm://0</acceptor>
  ...
</acceptors>

以上示例 接受代理接受 ID 为 0 的服务器的连接。其他服务器必须与代理在同一个虚拟机中运行。

将连接器配置为 in-vm 连接的语法如下:

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

上面示例中的 连接器 定义客户端如何建立与位于同一虚拟机中的 0 的服务器建立 in-VM 连接。客户端可以是应用程序或代理。

2.7. 从客户端配置连接

客户端应用程序中间接使用连接器。您可以直接在客户端上配置 JMS 连接工厂,而无需在服务器端定义 连接器

Map<String, Object> connectionParams = new HashMap<String, Object>();

connectionParams.put(org.apache.activemq.artemis.core.remoting.impl.netty.TransportConstants.PORT_PROP_NAME, 61617);

TransportConfiguration transportConfiguration =
    new TransportConfiguration(
    "org.apache.activemq.artemis.core.remoting.impl.netty.NettyConnectorFactory", connectionParams);

ConnectionFactory connectionFactory = ActiveMQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, transportConfiguration);

Connection jmsConnection = connectionFactory.createConnection();

第 3 章 网络连接:协议

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

代理支持以下协议:

注意

除上述协议外,代理还支持自己的原生协议,称为"Core Protocol"。过去版本的这个协议被称为"HornetQ",红帽 JBoss 企业应用平台使用。

3.1. 配置网络连接以使用协议

您必须将协议与网络连接关联,才能使用它。(请参阅 网络连接:接收器和连接器 以了解有关如何创建和配置网络连接的更多信息。 位于文件 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>

在给定网络 connnection 上启用 协议 的唯一要求是将 protocol 参数添加到接收器的 URI 中。参数的值必须是以逗号分开的协议名称列表。如果 URI 中没有 protocol 参数,则会启用所有协议。

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

  1. 打开配置文件 BROKER_INSTANCE_DIR/etc/broker.xml
  2. <acceptors> 小节中添加以下行:
<acceptor name="ampq">tcp://0.0.0.0:3232?protocols=AMQP</acceptor>

默认接受器中的其他参数

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

接受者.参数描述

all-protocols acceptor

AMQP

STOMP

tcpSendBufferSize

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

tcpReceiveBufferSize

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

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

摘要中,TCP 发送/接收方缓冲区大小应根据以下计算:

buffer_size = bandwidth * RTT.

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

对于 fast 网络,您可能想要从默认值增大缓冲区大小。

all-protocols acceptor

AMQP

STOMP

HornetQ

MQTT

useEpoll

如果使用支持它的系统(Linux),则使用 Netty epoll。Netty 原生传输提供比 NIO 传输更好的性能。此选项的默认值是 true。如果将 选项设置为 false,则使用 NIO。

all-protocols acceptor

AMQP

amqpCredits

AMQP 制作者可以发送的消息数上限,不论消息总大小如何。默认值为 1000

要了解有关如何使用信用控制 AMQP 消息的流,请参阅 第 10.2.3 节 “阻塞 AMQP 消息”

all-protocols acceptor

AMQP

amqpLowCredits

代理再分割制作者信贷的低阈值。默认值为 300。当制作者达到这个阈值时,代理发送制作者足够度,以恢复 amqpCredits 值。

要了解有关如何使用信用控制 AMQP 消息的流,请参阅 第 10.2.3 节 “阻塞 AMQP 消息”

HornetQ 兼容性接受器

anycastPrefix

当连接到使用任何广播和多播的地址时,客户端用来指定任何广播路由类型的前缀。 默认值为 jms.queue

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

multicastPrefix

当连接到使用任何广播和多播的地址时,客户端用来指定 多播路由 类型的前缀。默认值为 jms.topic

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

其他资源

3.2. 将 AMQP 与网络连接搭配使用

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

步骤

  1. 打开配置文件 BROKER_INSTANCE_DIR/etc/broker.xml
  2. 添加或配置 接收器,通过包含作为 URI 的一部分 AMQP 值的 protocol 参数来接收 AMQP 客户端,如下例所示:
<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 Core Protocol JMS。

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

3.2.2. 配置 AMQP 安全性

代理支持 AMQP SASL 身份验证。有关如何在代理上配置基于 SASL 的身份验证的更多信息,请参阅 安全性

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

代理支持 MQTT v3.1.1(以及旧的 v3.1 代码消息格式)。MQTT 是一个轻量级的客户端,发布到服务器,发布/订阅消息传递协议。MQTT reduce消息传递开销和网络流量,以及客户端的代码占用量。因此,MQTT 适用于限制传感器和国员等设备,并且很快成为了物联网(IoT)的实际标准通信协议。

步骤

  1. 打开配置文件 BROKER_INSTANCE_DIR/etc/broker.xml
  2. 添加启用 MQTT 协议的接受者。例如:
<acceptors>
  <acceptor name="mqtt">tcp://localhost:1883?protocols=MQTT</acceptor>
  ...
</acceptors>

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

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

关于 MQTT 协议的信息的最佳来源是在规范中。MQTT v3.1.1 规范可以从 OASIS 网站 下载。

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

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

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

步骤

  1. 打开配置文件 BROKER_INSTANCE_DIR/etc/broker.xml
  2. 添加或修改接受者,使其包含 OPENWIRE 作为协议 参数的一部分,如下例所示:

    <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. 打开配置文件 BROKER_INSTANCE_DIR/etc/broker.xml
  2. 配置现有的接收器或创建新接收器,并包含值为 STOMP 的 protocol 参数,如下所示。
<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 帧中的主机标头。
  2. 消息确认不是事务性的。ACK 帧不能是一个事务的一部分,如果设置了其 事务 标头,它将被忽略。

3.5.2. 为 STOMP 信息提供 ID

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

步骤

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

通过使用 stompEnableMessageId 参数,使用这个接收器发送的每个 STOMP 消息添加额外的属性。属性键是 amq-message-id,值是前缀为 STOMP 的内部消息 ID 的字符串,如下例所示:

amq-message-id : STOMP12345

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

3.5.3. 将连接时间设置为 Live(TTL)

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

步骤

  1. 打开配置文件 BROKER_INSTANCE_DIR/etc/broker.xml
  2. connectionTTL 参数添加到用于 STOMP 连接的接收器的 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,您可以使用核心功能来维护 STOMP 连接的生命周期。

将代理的默认时间覆盖为 Live(TTL)

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

步骤

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

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

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

STOMP 主要是一个文本指示协议。为了更加便于与 JMS 进行互操作,STOMP 实施检查 内容长度表明,决定如何将 STOMP 消息映射到 JMS。

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

JMS TextMessage

不包含 内容长度 的标头。

JMS BytesMessage

包含内容 长度 标题。

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

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

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

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

使用发送以下信息(header 和 body)的 STOMP 客户端示例:

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 目的地必须遵循相同的规范:

  • 通过由 jms.queue. 加上队列名称来发送或订阅 JMS Queue。例如,要将消息发送到 JMS Queue,STOMP 客户端必须发送该帧:

    SEND
    destination:jms.queue.orders
    hello queue orders
    ^@
  • 通过添加 topic name by jms.topic.,发送或订阅 JMS Topic。例如,要订阅到 stocks JMS Topic,STOMP 客户端必须发送类似如下的框架:

    SUBSCRIBE
    destination:jms.topic.stocks
    ^@

第 4 章 配置地址和队列

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

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

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

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

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

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

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

anycast

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

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 地址设置元素的配置,它会覆盖与 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。匹配每个地址.您可以继续应用此概括性,也可以在需要时为每个地址或一组地址添加新的 address-setting

news.europe.#

匹配 news.europe,news.europe.sport,news.europe.politics.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. 打开 <broker-instance-dir>/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 时,指示代理使用自定义设置。
    分隔符
    提供自定义字符,以将 用作 分隔符 而不是默认值,即
    any-words
    提供的字符作为 任意 单词的值用于表示"匹配零个或多个单词"序列,并将替换默认的 #。在表达式末尾使用此字符。
    单词
    提供的字符用作 单词的值表示"匹配单个单词",并将替换掉默认的 *。在您的表达式的任意位置使用此字符。

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

点对点的消息传递是常见的场景,由制作者发送的消息只有一个消费者。AMQP 和 JMS 消息制作者和使用者可以使用点对点的消息传递队列,例如:要确保与地址关联的队列以点对点的方式接收消息,您可以在代理配置中为给定 address 元素定义任何广播路由类型。

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

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

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

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

步骤

  1. 打开 <broker-instance-dir>/etc/broker.xml 配置文件。
  2. 地址 的所选 队列 元素中嵌套任何广播配置元素。确保 地址 和队列 元素的 name 属性的值相同。例如:

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

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

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

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

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

步骤

  1. 打开 <broker-instance-dir>/etc/broker.xml 配置文件。
  2. 围绕 address 元素中 的队列 元素嵌套任何广播配置元素。例如:

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

如果您的配置(如上方所示)在集群中的多个代理进行镜像,集群可以根据对生产者和消费者造成对点对点的消息传递进行负载平衡。确切的行为取决于为集群配置消息负载平衡策略的方式。

其他资源

4.4. 配置发布订阅消息传递的地址

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

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

下图显示了发布订阅消息传递的示例。

以下步骤演示了如何为发布订阅消息传递配置地址。

步骤

  1. 打开 <broker-instance-dir>/etc/broker.xml 配置文件。
  2. 在地址 中添加空的多播 配置元素。

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

    <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. 为点到点和发布订阅消息配置地址

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

通常不建议配置使用点到点和发布与发布与发布相关的语义的地址。但是,当您想要时,它很有用,例如,名为 order 的 JMS 队列,以及名为 order 的 JMS 主题。 不同的路由类型使地址在客户端连接上显示不同。在这种情况下,JMS 队列制作者发送的消息使用任何广播 路由 类型。由 JMS 主题制作者发送的消息使用 多播路由 类型。当 JMS 主题消费者连接到代理时,它将附加到自己的订阅队列。但是,JMS 队列消费者附加到任何广播 队列

下图显示了共同使用的点对点和发布订阅消息示例。

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

注意

这种情境的行为取决于所使用的协议。对于 JMS,主题和队列制作者和消费者之间有明确的区别,因此逻辑简单明了。AMQP 等其他协议没有这种区别。通过 AMQP 发送的消息默认被 任何 广播 和消费者 路由。如需更多信息,请参阅 第 3 章 网络连接:协议

步骤

  1. 打开 <broker-instance-dir>/etc/broker.xml 配置文件。
  2. 围绕 address 元素中 的队列 元素嵌套任何广播配置元素。例如:

    <configuration ...>
      <core ...>
        ...
        <address name="orders">
          <anycast>
            <queue name="orders"/>
          </anycast>
        </address>
      </core>
    </configuration>
  3. 在地址 中添加空的多播 配置元素。

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

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

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

通常,如果某个地址同时使用任何广播和多播收到消息,则任何广播队列之一接收该消息和所有 多播 队列。 但是,在连接到 地址时,客户端可以指定特殊前缀,以指定是否使用任何广播或 多播 进行连接。前缀是自定义值,使用代理配置中的 acceptor 的 URL 中任何cast PrefixmulticastPrefix 参数指定。

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

步骤

  1. 打开 <broker-instance-dir>/etc/broker.xml 配置文件。
  2. 对于给定的接收器,要配置任何广播前缀,请将任何cast Prefix 添加到配置的 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>

    根据上述配置,接收器配置为使用 anycast:// 进行任何广播前缀。客户端代码可以指定任何cast ://<my.destination>/,如果客户端只需要向任何广播队列之一发送消息。

  3. 对于给定的接受者,要配置 多播 前缀,请在配置的 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>/,如果客户端只需要发送到 多播 队列。

4.7. 配置订阅队列

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

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

4.7.1. 配置持久的订阅队列

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

步骤

  1. 打开 <broker-instance-dir>/etc/broker.xml 配置文件。
  2. 持久配置 元素添加到所选队列。设置值 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. 打开 <broker-instance-dir>/etc/broker.xml 配置文件。
  2. 持久配置 元素添加到每个所选队列。设置值 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. 打开 <broker-instance-dir>/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. 打开 <broker-instance-dir>/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 的 MQTT 订阅包时,MQTT 协议管理器了解这两个地址需要 多播 语义。因此,协议管理器首先查找以确保为这两个地址 启用多播。如果没有,它会尝试动态创建它们。如果成功,协议管理器将为客户端请求的每个订阅创建特殊订阅队列。

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

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

Durable subscription queue

查找适当的地址,并确保启用了 多播 语义。然后,它会创建一个特殊的订阅队列,其客户端 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. 配置分片队列

在队列中处理消息的常见模式,其中只需要部分排序才能使用 队列分片。这意味着您定义作为单个逻辑队列的任何广播地址,但由多个底层物理队列提供支持。

步骤

  1. 打开 <broker-instance-dir>/etc/broker.xml 配置文件。
  2. 添加 address 元素并设置 name 属性。例如:

    <configuration ...>
      <core ...>
        ...
        <addresses>
           <address name="my.sharded.address"></address>
        </addresses>
      </core>
    </configuration>
  3. 添加任何 广播 路由类型,并包含所需的分片队列数量。在以下示例中,队列 q1、q 2q3 会被添加为任何广播目的地。

    <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 的消息在 q 1、q2q3 之间均匀分布。在使用完全限定域名(FQQN)并将仅发送到该特定队列的消息时,客户端可以直接连接到特定的物理队列。

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

其他资源

4.11. 配置最后值队列

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

最后一个值队列的一个简单用例是监控股票价格,其中仅针对特定库存的最新值。

注意

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

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

以下流程演示了如何以下列方式配置最后的值队列。

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

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

  1. 打开 <broker-instance-dir>/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. 打开 <broker-instance-dir>/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_ticker 属性相同的 ATN 值。每条消息都有一个不同的值,称为 stock_price。每条消息都发送到同一个队列,即 price1

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 值为 value 键的消息(本例中为 ATN)到达 price 1 队列,且只有最新的消息保留在队列中,第一条消息会被清除。在命令行中输入以下行来验证此行为:

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

在本例中,您看到的输出是第二个消息,因为这两个消息都为最后一个值键使用相同的值,而第二个消息则在第一个队列中收到。

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

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

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

强制非破坏性消耗是最后值队列的实用配置,因为它确保队列始终包含特定最后值键的最新值。

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

先决条件

步骤

  1. 打开 <broker-instance-dir>/etc/broker.xml 配置文件。
  2. 如果您之前将队列配置为最后值队列,请添加 非破坏性 密钥。将值设为 true。例如:

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

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

    默认情况下,默认值非破坏性 的值是 false

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

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

4.12.1. 配置消息到期

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

步骤

  1. 打开 <broker-instance-dir>/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 值超过 expiration 时间的消息,代理会将过期时间设置为 max-expiry-delay 的指定的值。
    • 对于在 min-expiry-delay 值低于 expiration 时间的消息,代理会将过期时间设置为 min-expiry-delay 的指定的值。
    • 对于在 min-expiry-delaymax-expiry-delay 之间过期的消息,代理不会更改消息的过期时间。
    • 如果您为 expiry-delay (即默认值 -1)指定了一个值,这将覆盖您为 min-expiry-delaymax-expiry-delay 指定的任何值。
    • min-expiry-delaymax-expiry-delay 的默认值为 -1(即 disabled)。
  5. 在配置文件的 addresses 元素中,配置之前为 到期 地址指定的地址。在此地址上定义一个队列。例如:

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

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

4.12.2. 自动创建过期资源

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

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

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

先决条件

步骤

  1. 打开 <broker-instance-dir>/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> 元素来定义到期地址和关联的到期队列。自动创建的 <address> 元素的 name 值与为 <expiry-address> 指定的值匹配。

    自动创建的到期队列具有 多播路由 类型。默认情况下,代理将到期队列名称与最初发送消息的过期消息的地址匹配,例如 库存

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

    expiry-queue-prefix

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

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

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

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

注意

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

其他资源

4.13. 将未发送的消息移到死信地址

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

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

没有从死信队列消耗的消息具有以下属性:

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

4.13.1. 配置死信地址

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

步骤

  1. 打开 <broker-instance-dir>/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 address DLA
    max-delivery-attempts
    代理发出的最大发送尝试次数,然后向配置的死信地址移动未发送的消息。在这个示例中,代理会在三出失败传送尝试后将未发送的消息移到死信地址。默认值为 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. 打开 <broker-instance-dir>/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 ...>
  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,则代理会自动创建一个 <address> 元素来定义死信地址和关联的死信队列。自动创建的 <address> 元素的名称与您为 <dead-letter-address> 指定的 name 值匹配。

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

    代理还为死信队列定义过滤器,它使用 _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. 打开 <broker-instance-dir>/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. 打开 <broker-instance-dir>/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. 打开 <broker-instance-dir>/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. 打开 <broker-instance-dir>/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. 配置环队列

通常,AMQ Broker 中的队列使用先发(FIFO)语义。这意味着代理在队列的尾部添加信息,并将它们从头中删除。环队列是一种特殊的队列,它保存指定的固定消息数。当新消息到达时,代理通过删除队列头中的消息来维护固定队列大小,但队列已包含指定数量的消息。

例如,考虑配置了大小为 3 的 ring 队列,以及一个按顺序发送消息 A、B、C D 的制作者。消息 C 到达队列后,队列中的消息数量达到配置的环形大小。此时,消息 A 位于队列的头头,而消息 C 则位于尾部。当消息 D 到达队列时,代理会将消息添加到队列的尾部。为了维护固定队列大小,代理会从队列头删除消息(即消息 A)。消息 B 现在是队列的头部。

4.18.1. 配置环队列

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

步骤

  1. 打开 <broker-instance-dir>/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.18.2. 环队列故障排除

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

in-delivery 消息和回滚

当消息传送到消费者时,消息处于"在节点间的"状态,其中消息在技术上不再是队列中,但尚未被确认。消息会一直处于 in-delivery 状态,直到消费者确认。处于 in-delivery 状态的消息无法从环队列中删除。

因为代理无法删除 in-delivery 消息,所以客户端可以向环队列发送比环大小配置更多的消息。例如,请考虑这种情况:

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

    此时,messageCount= 3 和 deliver Count= 3

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

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

  4. 现在,假设使用者已关闭,且未被确认任何消息。

    在这种情况下,四个正在发送中,未确认的消息将被取消回代理,并按照它们使用的相反顺序添加到队列的头位。此操作会使队列超过配置的环形大小。由于环队列优先选择队列用于通过头上消息的尾部消息,因此队列会丢弃制作者发送的第一个消息,因为这是最后一个消息已重新添加到队列的头条。事务或核心会话回滚会采用同样的方式处理。

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

调度的消息

当计划的消息发送到队列时,不会立即将消息添加到队列的尾部,如普通消息。相反,代理将调度的消息保存在中间缓冲区中,并根据消息的详细信息,将消息传送到队列的头头。但是,调度的消息仍然反映在队列的消息计数中。与 in-delivery 消息一样,此行为可能会使得代理不强制实施环队列大小。例如,请考虑这种情况:

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

    此时,Message Count= 1scheduledCount= 1

  2. 在 12:01 上,生产者将消息 B 发送到同一个环队列。

    现在,MessageCount= 2scheduledCount= 1

  3. 在 12:02,生产者将消息 C 发送到同一个环队列。

    现在,MessageCount= 3scheduledCount= 1

  4. 在 12:03,生产者将消息 D 发送到同一个环队列。

    现在,MessageCount= 4scheduledCount= 1

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

paged 信息

与发送中的消息和消息类似,页面消息不计到由代理实施的环队列大小,因为消息实际是在地址级别上的分页,而不是队列级别。页面化消息在技术上不是队列的 messageCount 值,但它反映在队列的 messageCount 值中。

建议您不要将分页用于带有环队列的地址。相反,请确保整个地址可适应内存。或者,将 address-full-policy 参数设置为 DROP,BLOCKFAIL 值。

其他资源

4.19. 配置被动地址

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

当您配置 retroactive 地址时,代理创建一组名为 ring 队列 的内部实例。环队列是一种特殊的队列,它保存指定的固定消息数。队列达到指定大小后,到达队列的下一个消息会强制从队列发出最旧的消息。当您配置 retroactive 地址时,您间接指定内部环队列的大小。默认情况下,内部队列使用 多播路由 类型。

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

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

步骤

  1. 打开 <broker-instance-dir>/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 值。这个行为可以防止意外的消息丢失。在这种情况下,您需要使用 management API 手动减少环队列中的消息数量。

其他资源

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

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

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

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

步骤

  1. 打开 <broker-instance-dir>/etc/broker.xml 配置文件。
  2. 对于 OpenWire 连接器,添加 supportAdvisory 并将InternalManagementObjects 参数添加到配置的 URL。如本节前面所述设置值。例如:

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

4.21. 迭代地址和队列

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

例如,联合适合可靠地将消息从一个集群发送到另一个集群。此传输可能是跨广域网(WAN)、云基础架构的区域或互联网。如果从源代理到目标代理的连接会丢失(例如由于网络失败),则源代理会尝试重新建立连接,直到目标代理重新上线。当目标代理恢复在线时,消息传输会恢复。

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

在 AMQ Broker 中,两个主要联合选项是 地址联合 和队列联合。这些选项在以下几节中加以描述。

注意

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

4.21.1. 关于地址联合

地址联合是连接代理之间的完整多播分发模式。例如,发送到 BrokerA 上地址的每个消息都会被发送到该代理中的每个队列。另外,每个消息都会传送到 BrokerB 以及所有附加的队列。

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

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

4.21.2. 用于地址联合的常见拓扑

下面介绍了一些常用的地址联合拓扑。

对称拓扑

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

图 4.1. 对称拓扑中的问题进行联合

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

完整网格拓扑

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

图 4.2. 完整网格拓扑中的问题

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

Ring 拓扑

在 ring 的 ring 中,每个联合地址都是上游的。该拓扑示例如下所示。

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

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

环拓扑的一个优点是,在您需要进行的物理连接数量的情况下,设置得很便宜。但是,这种拓扑的缺陷在于,如果单个代理出现故障,整个环将会失败。

fan-out 拓扑

在 fan-out 拓扑中,一个 master 地址通过联合地址树链接到一起。发布到主地址的任何消息都可由连接到树中的任何代理的任何消费者接收。树形可以配置为任何深度。还可以扩展树,无需重新配置树中的现有代理。该拓扑示例如下所示。

图 4.4. 在 fan-out 拓扑中解决了问题

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

4.21.3. 支持在 address federation 配置中进行 movert 绑定

在配置地址联合时,您可以在地址策略配置中添加对 movert 绑定的支持。添加此支持使联合能够响应传播绑定,以在远程代理上为给定地址创建联合消费者。

例如,假设地址策略中包含一个名为 test.federation.source 的地址,并且不包括另一个名为 test.federation.target 的地址。通常,当在 test.federation.target 上创建队列时,这不会导致创建联合消费者,因为该地址不是地址策略的一部分。但是,如果您创建一个 movert 绑定,使得 test.federation.source 是源地址,test.federation.target 是转发地址,则会在转发地址中创建持久消费者。源地址仍然必须使用 多播路由 类型,但目标地址可以使用 多播或任何 广播。

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

4.21.4. 为代理集群配置联合

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

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

确保同一集群中的代理使用相同的联合配置、地址和队列策略名称来避免消息重复。例如,如果同一集群中的代理 具有不同的 联合配置名称,则可能会导致出现一个情况,因为为同一地址创建多个不同命名转发队列,从而导致下游用户出现消息重复。相反,如果同一集群中的代理 使用相同的 联合配置名称,则基本上会创建复制的、集群转发队列,这些队列负载平衡到下游用户。这可避免消息重复。

4.21.5. 配置上游地址联合

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

先决条件

步骤

  1. 打开 <broker-instance-dir>/etc/broker.xml 配置文件。
  2. 添加包含 <federation> 元素的新 <federations> 元素。例如:

    <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 可按需侦听绑定。如果一个与地址策略包含的地址匹配的地址有 movert 绑定,则与 movert 转发地址匹配的任何队列绑定都将创建需要。默认值为:false
    max-hops
    联合期间可以发出消息的最大跃点数。特定拓扑需要此属性的特定值。要了解更多有关这些要求的信息,请参阅 第 4.21.2 节 “用于地址联合的常见拓扑”
    transformer-ref
    转换器配置的名称。如果要在联合消息传输过程中转换信息,可以添加转换器配置。此流程稍后会描述转换器配置。
  4. <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">
    
                <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.activemq.core.server.transformer.Transformer 接口的用户定义的类的名称。

    转换器的 transform() 方法会在消息被传输之前通过消息调用。这可让您在联合邮件标头或正文前转换该邮件标头或正文。

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

    <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
    包含连接器( connector-ref )元素列表,它引用本地代理的 broker.xml 配置文件中定义的 连接器 元素。连接器定义要用于传出连接的传输(TCP、SSL、HTTP 等)和服务器连接参数(主机、端口等)。此步骤的下一步演示了如何添加在 static-connectors 元素中引用的连接器。
    policy-ref
    在应用于上游代理的下游代理上配置的地址策略的名称。

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

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

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

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

注意

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

先决条件

步骤

  1. 在本地代理上,打开 <broker-instance-dir>/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. 为每个远程代理添加 下游 元素。例如:

    <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>
    connector name="netty-connector"
    本地代理发送到远程代理的连接器配置。远程代理使用此配置来连接本地代理。
    连接器名称="eu-west-1-connector", connector name="eu-east-1-connector"
    远程代理连接器。本地代理使用这些连接器连接到远程代理,并共享远程代理需要连接本地代理的配置。
    acceptor name="netty-acceptor"
    接受与远程代理用来连接到本地代理的连接器相对应的本地代理。

4.21.7. 关于队列联合

队列联合提供了一种在其他远程代理本地代理中平衡单个队列负载的方法。

为实现负载平衡,本地代理从远程队列检索消息,以满足本地消费者的消息需求。示例如下所示:

图 4.5. 对称队列联合

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

4.21.7.1. 队列联合的优点

下文介绍了一些您可能选择配置队列联合的原因。

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

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

图 4.6. 多区域队列联合

在安全企业 LAN 和 DMZ 之间通信

在网络安全中,非军事区 (DMZ)是一个物理或逻辑子网,其中包含并公开一个企业的外部服务到不被信任的服务,通常是较大的网络,如互联网。企业本地区域网络(LAN)的其余部分保持与防火墙后面的这个外部网络隔离。

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

4.21.8. 配置上游队列联合

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

先决条件

步骤

  1. 打开 <broker-instance-dir>/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> 元素的属性值。例如:

    <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
    队列策略的名称。代理上配置的所有队列策略都必须具有唯一的名称。
    include-federated

    当此属性的值设置为 false 时,配置不会重新影响已经受到影响的消费者(即联合队列上的使用者)。这可避免发生在对称或闭环拓扑中的情形,没有非破坏消费者,并在系统中最终出现消息流。

    如果您没有 闭环拓扑,您可以将此属性的值设置为 true。例如,假设您有三个代理( BrokerABrokerB、BrokerB 和 BrokerC )的链,在 BrokerA 和消费者在 BrokerC 上有一个消费者。在这种情况下,您希望 BrokerB 重新将消费者重新变为 BrokerA

    Priority-adjustment
    当消费者连接到队列时,在创建上游( 联合)消费者时使用其优先级。federated consumer 的优先级根据 priority-adjustment 属性的值调整。这个属性的默认值为 -1,这样可确保本地使用者在负载均衡期间优先于联合消费者。但是,您可以根据需要更改优先级调整的值。
    transformer-ref
    转换器配置的名称。如果要在联合消息传输过程中转换信息,可以添加转换器配置。此流程稍后会描述转换器配置。
  4. <queue-policy> 元素中,添加地址匹配模式以包括队列策略中的地址和排除地址。例如:

    <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 结尾的队列都将被排除。这表明某些队列保留为本地队列,而不是联合。
  5. 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
    转换器配置的名称。这个名称在代理上必须是唯一的。您可以将这个名称指定为 address 策略的 transformer-ref 属性的值。
    class-name

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

    转换器的 transform() 方法会在消息被传输之前通过消息调用。这可让您在联合邮件标头或正文前转换该邮件标头或正文。

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

    <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
    包含连接器( connector-ref )元素列表,它引用本地代理的 broker.xml 配置文件中定义的 连接器 元素。连接器定义要用于传出连接的传输(TCP、SSL、HTTP 等)和服务器连接参数(主机、端口等)。此步骤的以下步骤演示了如何添加联合队列配置 的静态 连接器元素所引用的连接器。
    policy-ref
    在应用到上游代理的下游代理上配置的队列策略的名称。

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

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

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

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

注意

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

先决条件

步骤

  1. 打开 <broker-instance-dir>/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. 为每个远程代理添加 下游 元素。例如:

    <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>
    connector name="netty-connector"
    本地代理发送到远程代理的连接器配置。远程代理使用此配置来连接本地代理。
    connector name="eu-west-1-connector" , connector name="eu-east-1-connector"
    远程代理连接器。本地代理使用这些连接器连接到远程代理,并共享远程代理需要连接本地代理的配置。
    acceptor name="netty-acceptor"
    接受与远程代理用来连接到本地代理的连接器相对应的本地代理。

第 5 章 安全代理

5.1. 保护连接

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

您可以使用两个 TLS 配置:

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

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

5.1.1. 配置单向 TLS

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

  1. 打开 <broker-instance-dir>/etc/broker.xml 配置文件。
  2. 对于给定的接受者,请添加 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. 打开 <broker-instance-dir>/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

在接受者中使用:代理上的密钥存储的密码。

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

trustStorePath

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

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

trustStorePassword

在接受者中使用:代理中信任存储的密码。只有在您使用双向 TLS 时,这才与接受者相关。

连接器使用时:客户端中信任存储的密码。虽然您可以在代理上配置此值,但客户端已下载并使用它。如果客户端需要使用代理上设置的不同密码,那么它可使用标准的 javax.net.ssl.trustStorePassword 系统属性或 AMQ 特定的 org.apache.activemq.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. 打开 <broker-instance-dir>/etc/login.config 配置文件。默认情况下,在新的 AMQ Broker 7.8 实例中,这个文件包括以下行:

    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 需要什么级别的成功级别。您可以设置的值有:

    • 必需 :登录模块需要成功。身份验证继续关闭在给定别名中配置的登录模块列表,无论成功还是失败。
    • 必要 :登录模块需要成功。故障会立即向应用返回控制权。身份验证不会关闭在给定别名中配置的登录模块列表。
    • 足够:成功不需要登录模块。如果成功,则控制权返回到应用程序,身份验证也不会进一步进行。如果失败,身份验证将尝试关闭在给定别名中配置的登录模块列表。
    • 可选 :成功不需要登录模块。无论成功还是失败,身份验证都会保留在给定别名中配置的登录模块列表。
    org.apache.activemq.jaas.properties.user
    指定为登录模块实施定义一组用户和密码的属性文件。
    org.apache.activemq.jaas.properties.role
    指定将用户映射到已定义登录模块实施的角色的属性文件。
  2. 打开 <broker-instance-dir>/etc/artemis-users.properties 配置文件。
  3. 添加用户并为用户分配密码。例如:

    user1=secret
    user2=access
    user3=myPassword
  4. 打开 <broker-instance-dir>/etc/artemis-roles.properties 配置文件。
  5. 为您之前添加到 artemis-users.properties 文件中的用户分配角色名称。例如:

    admin=user1,user2
    developer=user3
  6. 打开 <broker-instance-dir>/etc/bootstrap.xml 配置文件。
  7. 如有必要,将您的安全域别名(在这个实例中,activemq)添加到 文件中,如下所示:

    <jaas-security domain="activemq"/>

5.2.2.2. 配置客户机访问

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

您可以使用 命令行参数创建启用客户机访问的代理实例;-- allow-anonymous (与 --require-login相对应)。

以下步骤演示了如何配置客户机访问。

先决条件

步骤

  1. 打开之前为基本身份验证配置的 <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. 从之前导入到代理密钥存储的用户证书获取 Subjectuish ed Names (DN)。

    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。输入对象 DN 的格式取决于您的平台。以上字符串也可以表示为:

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

    1. 打开 <broker-instance-dir>/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. 打开 <broker-instance-dir>/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. 打开 <broker-instance-dir>/etc/artemis-roles.properties 配置文件。此文件中定义了可用的角色和存放这些角色的用户。例如:

      admins=system
      users=system,user
      guests=guest

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

    4. 确保您的安全域别名(在这个实例中,activemq)在 bootstrap.xml 中被引用,如下所示:

      <jaas-security domain="activemq"/>

5.2.3.2. 为 AMQP 客户端配置基于证书的验证

使用 简单身份验证和安全层 (SASL)EXTERNAL 机制配置参数,在连接到代理时为基于证书的验证配置基于证书的 AQMP 客户端。

代理验证 AMQP 客户端的 传输层安全 (TLS)/安全套接字层 (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> 元素针对队列(基于其地址)定义。您可以在 配置文件的 <security-settings> 元素中定义多个 <security-setting> 实例。您可以指定准确的地址匹配,也可以使用数字符号(#)和星号(*)通配符字符来定义通配符匹配。

可将不同的权限分配给与地址匹配的一组队列。这些权限在下表中显示。

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

创建地址

createAddress

删除地址

deleteAddress

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

createDurableQueue

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

deleteDurableQueue

在匹配的地址下创建一个不可中断的队列

createNonDurableQueue

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

deleteNonDurableQueue

向匹配的地址发送消息

send

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

consume

通过向管理地址发送管理消息来调用管理操作

管理

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

浏览

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

以下部分显示一些权限配置示例。

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

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

步骤

  1. 打开 <broker-instance-dir>/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>

    根据前面的配置,producer 角色的成员具有地址 my.destination发送 权限。

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

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

步骤

  1. 打开 <broker-instance-dir>/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.destination

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

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

步骤

  1. 打开 <broker-instance-dir>/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>

    根据前面的配置,所有权限都会被授予所有队列上 guest 角色的成员。在配置了匿名身份验证以为每个用户分配 guest 角色的开发场景中非常有用。

其他资源

5.3.2.1.4. 配置多个安全设置

以下示例步骤演示了如何为一组匹配的地址单独配置多个安全设置。这与本节中的示例不同,它演示了如何 授予对所有 地址的完整访问权限。

  1. 打开 <broker-instance-dir>/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开头的任何地址。
    permission type="createDurableQueue"
    只有具有 admin 角色的用户才能创建或删除与字符串 globalqueues.europe开头的地址的持久队列。
    permission type="createNonDurableQueue"
    任何具有 admin 角色、guesteurope-users 的用户都可以创建和删除绑定到以字符串 globalqueues.europe开头的地址的临时队列。
    permission type="send"
    任何具有 admineurope-users 角色的用户都可以发送消息到以字符串 globalqueues.europe开头的地址。
    permission type="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 不会 继承该文件中的第一个 security-setting 元素。例如,对于地址 globalqueues.europe.orders.plastics,存在的唯一权限是 发送和 使用 角色 europe-users

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

5.3.2.1.5. 使用用户配置队列

自动创建队列时,队列将分配连接客户端的用户名。此用户名作为元数据包含在队列中。名称通过 JMX 并在 AMQ Broker 管理控制台中公开。

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

步骤

  1. 打开 <broker-instance-dir>/etc/broker.xml 配置文件。
  2. 对于给定队列,添加用户 密钥。分配值。例如:

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

    根据前面的配置,admin 用户分配到队列 ExampleQueue

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

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

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

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

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

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

先决条件

步骤

  1. 打开 <broker-instance-dir>/etc/broker.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>
    • 在本例中,匹配应用于具有域名 org.apache.activemq.apache 的任何 MBean 属性。
    • 对匹配的 MBean 属性的 viewupdateamq 角色的访问由 列表*( get* set*set* )和 * 访问方法添加到其中。method="*" (wildcard)语法用作概括性方法,用于指定配置中没有列出的每个其它方法。配置中的每个访问方法都转换为 MBean 方法调用。
    • 调用的 MBean 方法与配置中列出的方法进行匹配。例如,如果您在具有 org.apache.activemq.artemis 域的 MBean 上调用一个名为 listMessages 的方法,则代理会将访问匹配回 列表 方法中定义的角色。
    • 您还可以使用完整的 MBean 方法名称来配置访问权限。例如:

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

    • 在 Linux 上: <broker-instance-dir>/bin/artemis run
    • 在 Windows 上:& lt;broker-instance-dir>\bin\artemis-service.exe start

您还可以通过添加与 MBean 属性匹配的 密钥 属性来匹配域中的特定 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 属性将角色映射到特定命名队列。在本例中,命名队列是 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>

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

<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>

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

例如,考虑配置两个 <match> 元素:

<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.artemis 的队列与两个通配符键表达式匹配。因此,代理需要优先选择一组要映射到队列的角色、第一个匹配元素中指定的角色,或者第二个 匹配 元素中指定的角色。

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

  • 完全匹配优先于通配符匹配
  • 较长的通配符匹配优先于较短的通配符匹配

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

注意

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

5.3.2.2.3. 配置白名单元素

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

以下示例步骤演示了如何配置 whitelist 元素。

步骤

  1. 打开 <broker_instance_dir>/etc/management.xml 配置文件。
  2. 搜索 白名单 元素并编辑配置:

    <whitelist>
       <entry domain="hawtio"/>
    </whitelist>

    在本例中,任何带有域 hawtio 的 MBean 都被允许访问且无身份验证。您还可以为要匹配的 MBean 属性使用 <entry domain="hawtio" key="type=*"/> 格式的通配符条目。

  3. 启动或重启代理。

    • On Linux: <broker_instance_dir>/bin/artemis run
    • On Windows: <broker_instance_dir>\bin\artemis-service.exe start

5.3.2.3. 设置资源限值

有时,除了与授权和身份验证相关的一般安全设置外,设置特定限制会有一些限制。

5.3.2.3.1. 配置连接和队列限制

以下示例步骤演示了如何限制用户可以创建的连接和队列数量。

  1. 打开 <broker-instance-dir>/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 中指定的匹配字符串 无法 使用通配符语法。相反,匹配字符串会定义一个将资源限制设置应用到的特定用户。

5.4. 使用 LDAP 进行身份验证和授权

LDAP 登录模块通过根据中央 X.500 目录服务器中存储的用户数据检查传入的凭据来启用身份验证和授权。它由 org.apache.activemq.artemis.spi.core.security.jaas.LDAPLoginModule 实施。

5.4.1. 配置 LDAP 以验证客户端

以下示例步骤演示了如何使用 LDAP 验证客户端。

步骤

  1. 打开 <broker-instance-dir>/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. 打开 <broker-instance-dir>/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

      指定代理可以连接到目录服务器的最长时间,以毫秒为单位。如果代理无法在此时间内连接到目录 s,它将会中止连接尝试。如果您为此属性指定零或小于值,则使用底层 TCP 协议的超时值。如果没有指定值,代理会无限期等待建立连接,或者底层网络超时。

      当为连接池请求了连接池时,此属性指定代理在达到最大池大小且池中所有连接都处于连接的最长时间。如果您指定了零或更少值,则代理会无限期等待连接可用。否则,代理会在达到最长等待时间时中止连接尝试。

      身份验证
      指定绑定到 LDAP 服务器时使用的身份验证方法。这个参数可以设置为 简单 (需要用户名和密码)或 none (允许匿名访问)。
      userBase
      选择 DIT 的特定子树来搜索用户条目。子树通过 DN 指定,用于指定子树的基本节点。例如,将此选项设置为 ou=User,ou=ActiveMQ,ou=system,ou=system,搜索用户条目仅限于 ou=User,ou=ActiveMQ,ou=system 节点下的子树。
      userSearchMatching
      指定一个 LDAP 搜索过滤器,它应用到 userBase 选择的子树。详情请查看下面的 第 5.4.1.1 节 “搜索匹配参数” 部分。
      userSearchSubtree
      相对于由 userBase 指定的节点,指定用户条目的搜索深度。此选项是一个布尔值。指定一个 false 值表示搜索尝试匹配 用户Base 节点的其中一个子条目(映射到 javax.naming.directory.SearchControls.ONELEVEL_SCOPE)。指定一个 true 值表示搜索尝试匹配 属于用户Base 节点 的子树 的任何条目(映射到 javax.naming.directory.SearchControls.SUBTREE_SCOPE)。
      userRoleName
      user 条目的属性名称,其中包含用户的角色名称列表。角色名称由代理的授权插件解析为组名称。如果省略这个选项,则不会从用户条目中提取角色名称。
      readTimeout
      指定代理可以等待从目录服务器到 LDAP 请求的响应的最长时间,以毫秒为单位。如果代理没有从目录服务器接收响应,代理会中止请求。如果您指定一个零个或更少值,或者您没有指定值,则代理会无限期等待目录服务器中的响应进入 LDAP 请求。
      roleBase
      如果角色数据直接存储在目录服务器中,则可以使用角色选项(角色BaseroleSearchMatchingroleSearchSubtreeroleName)的组合来指定 userRoleName 选项。这个选项选择 DIT 的特定子树来搜索 role/group 条目。子树通过 DN 指定,用于指定子树的基本节点。例如,将此选项设置为 ou=Group,ou=ActiveMQ,ou=system,ou=system ,ou=system 条目的搜索仅限于 ou=Group,ou=ActiveMQ,ou=system node 下的子树。
      roleName
      角色条目的属性类型,其中包含角色/组的名称(如 C、O、OU 等)。如果忽略了这个选项,则有效禁用角色搜索功能。
      roleSearchMatching
      指定 LDAP 搜索过滤器,它应用到 roleBase 选择的子树。详情请查看下面的 第 5.4.1.1 节 “搜索匹配参数” 部分。
      roleSearchSubtree

      根据 roleBase 指定的节点,指定角色条目的搜索深度。如果设置为 false (默认为 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. 启动或重启代理(服务或进程)。

5.4.1.1. 搜索匹配参数

userSearchMatching

在传递给 LDAP 搜索操作前,该配置参数提供的字符串值将受到字符串替换的约束,如 java.text.MessageFormat 类所实施。

这意味着,特殊的字符串 {0} 将被用户名替换,如从传入客户端凭证中提取。替换后,字符串将解释为 LDAP 搜索过滤器(语法由 IETF 标准 RFC 2254)定义。

例如,如果将这个选项设置为 (uid={0}),并且收到的用户名是 jdoe,则搜索过滤器在字符串替换后变成 (uid=jdoe)

如果生成的搜索过滤器应用到用户群选择的子树,ou=User,ou=ActiveMQ,ou=system,ou=system 可与条目 uid=jdoe,ou=User,ou=ActiveMQ,ou=system 相匹配。

roleSearchMatching

这的工作方式与 userSearchMatching 选项类似,但它支持两个替换字符串。

替换字符串 {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,它将与 member 属性等于 uid=jdoe 的所有角色条目匹配( member 属性的值是 DN)。

必须始终设置这个选项,即使角色搜索被禁用,因为它没有默认值。如果使用 OpenLDAP,搜索过滤器的语法为 (member:=uid=jdoe)。

其他资源

5.4.2. 配置 LDAP 授权

LegacyLDAPSecuritySettingPlugin 安全设置插件读取以前由 LDAPAuthorizationMap 和 cache LDAPAuthorizationMap 中处理的安全信息,并在可能的情况下将这些信息转换为对应的 AMQ 7 安全设置。

AMQ 6 和 AMQ 7 中的代理安全实施不完全匹配。因此,插件在两个版本之间执行一些转换,以实现接近的等效功能。

以下示例演示了如何配置插件。

步骤

  1. 打开 <broker-instance-dir>/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。默认值为 ou=destinations,o=ActiveMQ,ou=system
filter
指定 LDAP 搜索过滤器,该过滤器在查找任何类型的目的地时使用。搜索过滤器尝试匹配队列或主题节点的子子或后代。默认值为 (cn=*)
roleAttribute
通过 过滤器 指定节点的属性,其值为 role 的 DN。默认值为 uniqueMember
adminPermissionValue
指定与 admin 权限匹配的值。默认值为 admin
readPermissionValue
指定与 读取权限 匹配的值。默认值为
writePermissionValue
指定与 写入权限 匹配的值。默认值为 write
enableListener
指定是否启用自动接收 LDAP 服务器中的更新并实时更新代理的授权配置。默认值为 true
mapAdminToManage

指定是否将旧的(即 AMQ 6) 管理权限 映射到 AMQ 7 管理权限。请参阅下表中映射语义的详情。默认值为:false

在 LDAP 中定义的队列或主题的名称充当安全设置的"匹配",权限值从 AMQ 6 类型映射到 AMQ 7 类型,角色映射为 is-is。由于 LDAP 中定义的队列或主题的名称充当安全设置的匹配项,因此安全设置可能无法按预期应用到 JMS 目的地。这是因为 AMQ 7 始终以"jms.queue."或"jms.topic."前缀 JMS 目的地。

AMQ 6 有三种权限类型 - 读取写入admin。ActiveMQ 网站上介绍了这些权限类型; 安全

AMQ 7 有以下权限类型:

  • createAddress
  • deleteAddress
  • createDurableQueue
  • deleteDurableQueue
  • createNonDurableQueue
  • deleteNonDurableQueue
  • send
  • consume
  • 管理
  • 浏览

    下表显示了安全设置插件如何将 AMQ 6 权限类型映射到 AMQ 7 权限类型:

    AMQ 6 权限类型AMQ 7 权限类型

    读取

    使用、浏览

    write

    send

    admin

    createAddress, deleteAddress, createDurableQueue, deleteDurableQueue, createNonDurableQueue, deleteNonDurableQueue, manage (如果 mapAdminToManage 设置为 true

    如下所述,在有些情况下,插件在 AMQ 6 和 AMQ 7 权限类型之间执行一些转换,以实现评估:

    • 默认情况下,映射不包含 AMQ 7 管理 权限类型,因为 AMQ 6 中没有类似的权限类型。但是,如果 mapAdminToManage 设置为 true,则插件会将 AMQ 6 admin 权限映射到 AMQ 7 管理权限
    • AMQ 6 中的 admin 权限类型决定了代理是否自动创建目的地(如果目标不存在且用户向其发送信息)。如果用户有权限将消息发送到目的地,AMQ 7 会自动允许自动创建目标。因此,默认情况下,插件将旧 管理权限 映射到上述 AMQ 7 权限。如果 mapAdminToManage 设置为 true,则插件还会将 AMQ 6 admin 权限映射到 AMQ 7 管理权限

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. 打开 <broker_instance_dir>/etc/login.config 文件。找到 connectionPassword 参数:

    connectionPassword = <password>
  3. 使用加密值替换 plain-text 密码:

    connectionPassword = 3a34fd21b82bf2a822fa49a8d8fa115d
  4. 使用标识符 "ENC()" 打包加密值:

    connectionPassword = "ENC(3a34fd21b82bf2a822fa49a8d8fa115d)"

login.config 文件现在包含已屏蔽的密码。因为密码被嵌套为 "ENC()" 标识符,AMQ Broker 会在使用前对其进行解密。

其他资源

5.5. 使用 Kerberos 进行身份验证和授权

在使用 AMQP 协议发送和接收消息时,客户端可以使用 简单身份验证和安全层 (SASL)框架的 GSSAPI 机制发送 AMQ Broker 验证的 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. 打开 <broker_instance_dir>/etc/broker.xml 配置文件。
  3. 将 name-value 对 saslMechanisms=GSSAPI 添加到接收器 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. 打开 <broker_instance_dir>/etc/login.config 配置文件。
  3. 添加名为 amqp-sasl-gssapi 的配置范围。以下示例显示了在 JDK 的 Oracle 和 OpenJDK 版本中找到的 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 的 Oracle 和 OpenJDK 版本提供。通过引用 Java 供应商的文档,验证 Krb5LoginModule 及其可用选项的完全限定类名称。
    useKeyTab
    Krb5LoginModule 在验证主体时使用 Kerberos keytab。keytabs 使用来自 Kerberos 环境的工具生成。有关生成 Kerberos keytab 的详情,请查看您的厂商文档。
    principal
    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,作为 AMQ Broker UserPrincipal。然后,可以将凭证传递给 PropertiesLoginModuleLDAPLoginModule 模块,它将 Kerberos 验证的 Peer 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. 打开 <broker_instance_dir>/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 使用 org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager 安全管理器。此默认安全管理器提供与 JAAS 和红帽 JBoss 企业应用平台(JBoss EAP)安全性的集成。

但是,系统管理员可能希望更多地控制代理安全性。在这种情况下,可以在代理配置中指定自定义安全管理器。自定义安全管理器是用户定义的类,用于实施 org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager5 接口。

5.6.1. 指定自定义安全管理器

以下流程演示了如何在代理配置中指定自定义安全管理器。

步骤

  1. 打开 <broker-instance-dir>/etc/boostrap.xml 配置文件。
  2. class-name 属性的 security-manager 元素中,指定 class 是 org.apache.activemq.artemis.spi.core.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.2. 运行自定义安全管理器示例程序

AMQ Broker 包括一个示例程序,它演示了如何实施自定义安全管理器。在示例中,自定义安全管理器记录身份验证和授权的详细信息,然后将详细信息传递给 org.apache.activemq.artemis.spi.core.security.ActiveMQJAASSecurityManager (默认的安全管理器)。

以下步骤演示了如何运行自定义安全管理器示例程序。

先决条件

  • 您的计算机必须设置为运行 AMQ Broker 示例程序。如需更多信息,请参阅 运行 AMQ Broker 示例

步骤

  1. 导航到 目录,前往包含自定义安全管理器示例的目录。

    $ cd <install-dir>/examples/features/standard/security-manager
  2. 运行 示例。

    $ mvn verify
注意

如果您要在运行示例程序时手动创建并启动代理实例,请将上一步中的命令替换为 mvn -PnoServer 验证

5.7. 禁用安全性

安全性 默认为启用。以下流程演示了如何禁用代理安全。

步骤

  1. 打开 <broker-instance-dir>/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 协议的违反情况。

对于基于其/并 SSL 证书验证的用户,代理填充的验证用户名是证书区分名称(DN)映射的名称。

broker.xml 配置文件中,如果启用了 security-enabledpopulate-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

注意

Artemis-users.properties 仅支持已散列化的屏蔽密码。在创建代理时创建用户时,rte mis-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. 打开 <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 会在使用前对其进行解密。

其他资源

第 6 章 持久性消息

本章论述了持久性如何与 AMQ Broker 合作以及如何配置它。

代理随附两个持久性选项:

  1. 基于 journal

    默认值。将消息写入文件系统中日志的高性能选项。

  2. JDBC-based

    使用代理的 JDBC 存储将消息保留到您选择的数据库中。

另外,您还可以 为零持久性配置代理

代理使用不同的解决方案来持久保留消息日志外的大信息。如需更多信息,请参阅使用大型消息。代理也可以配置为在内存不足的情况下将消息记录到磁盘。如需更多信息 ,请参阅 和管理消息。

注意

有关支持哪些数据库和网络文件系统的当前信息,请参阅红帽客户门户网站中的 Red Hat AMQ 7 支持的配置

6.1. 关于基于日志的持久性

代理的日志是仅 附加磁盘上的文件 集合。每个文件预先创建为固定的大小,最初使用 padding 填充。当消息传递操作在代理上执行时,记录会附加到日志末尾。附加记录可让代理最小化磁盘头移动和随机访问操作,这通常是磁盘上的最慢的操作。当一个日志文件已满时,代理会使用一个新的日志文件。

日志文件的大小可配置,从而最大程度减少每个文件所使用的磁盘柱面的数量。但是,现代磁盘拓扑比较复杂,代理无法控制该文件所映射到的柱面。因此,日志文件大小并非精确的科学。

其他与持久性相关的功能包括:

  • 确定特定日志文件仍在使用中的复杂文件垃圾回收算法。如果没有,可以回收并重新使用该文件。
  • 一个紧凑算法,它从日志中删除死空间,并压缩数据。这会导致日志使用较少的磁盘上的文件。
  • 支持本地事务。
  • 在使用 AMQ JMS 客户端时支持 XA 事务。

大多数日志使用 Java 编写。但是,抽象与实际文件系统的交互是抽象的,因此您可以使用不同的、可插拔式的实现。AMQ Broker 附带两个实现:

  • Java NIO.

    使用标准 Java NIO 与文件系统接口。这可提供极好的性能,并在带有 Java 6 或更高版本运行时的任何平台上运行。

  • Linux Asynchronous IO

    使用精简原生打包程序与 Linux 异步 IO 库(AIO)进行通信。使用 AIO 时,代理会在数据变为磁盘后调用,避免完全进行显式同步。默认情况下,代理尝试使用 AIO 日志,并在 AIO 不可用时回退到使用 NIO。

    使用 AIO 时的性能优于使用 Java NIO 时。有关如何安装 libaio 的说明,请参阅使用 AIO 日志

注意

有关支持哪些网络文件系统的当前信息,请参阅红帽客户门户网站中的 Red Hat AMQ 7 支持的配置

6.1.1. 使用 AIO

Java NIO 日志非常高性能,但如果您正在运行使用 Linux 内核 2.6 或更高版本的代理,红帽建议使用 AIO 日志来提高性能。不可与其它操作系统或早期版本的 Linux 内核一起使用 AIO 日志。

要使用 AIO 日志,如果 libaio 尚未安装,则必须安装 libaio。

步骤

  • 使用 yum 命令安装 libaio,如下例所示:
yum install libaio

6.2. 配置基于日志的持久性

持久性配置在文件 BROKER_INSTANCE_DIR/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>
    ...
  </core>
</configuration>
启用持久性
指定是否将基于文件的日志用于消息持久性。
journal-type
要使用的日志类型。如果设置为 ASYNCIO,则代理首先尝试使用 AIO。如果没有找到 ASYNCIO,则代理会返回 NIO。
bindings-directory
绑定日志的文件系统位置。默认设置为 BROKER_INSTANCE_DIR
journal-directory
消息传递日志的文件系统位置。默认设置为 BROKER_INSTANCE_DIR
journal-datasync
指定是否使用 fdatasync 确认对磁盘的写入操作。
journal-min-files
代理启动时要创建的日志文件数量。
journal-pool-files
回收未使用的文件后要保留的文件数量。默认值 -1 表示在清理过程中不会删除任何文件。

6.2.1. Message Journal

消息日志存储所有与消息相关的数据,包括消息本身和重复的 ID 缓存。此日志上的文件的前缀为 activemq-data。每个文件都有一个 amq 扩展名,默认大小为 10485760 字节。使用 journal-directory 配置元素设置消息日志的位置。默认值为 BROKER_INSTANCE_DIR/data/journal。默认配置包含与消息传递日志相关的其他元素:

  • journal-min-files

    代理启动时预先创建的日志文件数量。默认值为 2

  • journal-pool-files

    回收未使用的文件后要保留的文件数量。默认值 -1 表示代理创建后不会删除任何文件。但是,该系统不能无限增加,因此您需要将分页用于未绑定的目的地。如需更多信息,请参阅关于使用消息 的章节。

消息传递日志提供了其他一些配置元素。有关 完整的列表,请参见附录

6.2.2. Bindings Journal

绑定日志用于存储与绑定相关的数据,如服务器上部署的一组队列及其属性。它还存储 ID 序列计数器等数据。

绑定日志总是使用 NIO,因为与消息日志相比,其吞吐量通常较低。此日志上的文件的前缀为 activemq-bindings。每个文件都有一个 绑定 扩展名,默认大小为 1048576 字节

使用 BROKER_INSTANCE_DIR/etc/broker.xml 中的以下配置元素来配置绑定日志。

  • bindings-directory

    这是绑定日志所在的目录。默认值为 BROKER_INSTANCE_DIR/data/bindings

  • create-bindings-dir

    如果设为 true,则绑定目录会在绑定目录中指定的位置自动创建(如果 绑定 目录尚不存在)。默认值为 true

6.2.3. JMS 日志

JMS 日志存储所有 JMS 相关数据,包括 JMS Queues、主题和连接因素,以及这些资源的任何 JNDI 绑定。另外,通过管理 API 创建的任何 JMS 资源都会保留至该日志,但通过配置文件配置的任何资源都不会。只有在使用 JMS 时,才会创建 JMS 日志。

此日志上的文件前缀为 activemq-jms。每个文件都有一个 jms 扩展名,默认大小为 1048576 字节

JMS 日志将其配置与绑定日志共享。

6.2.4. 编译日志文件

AMQ Broker 包含一个紧凑算法,它从日志中删除死空间并压缩其数据,以便在磁盘上占用较少的空间。有两个标准用来决定何时启动压缩。满足这两个条件后,紧凑过程会解析日志并删除所有死记录。因此,日志包含较少的文件。条件为:

  • 为日志创建的文件数量。
  • 日志文件中实时数据的百分比。

您可以在 BROKER_INSTANCE_DIR/etc/broker.xml 中配置这两个条件。

步骤

  • 要配置紧凑过程的标准,请添加以下两个元素,如下例所示。

    <configuration>
      <core>
        ...
        <journal-compact-min-files>15</journal-compact-min-files> 1
        <journal-compact-percentage>25</journal-compact-percentage>  2
        ...
      </core>
    </configuration>
    1
    在压缩开始前创建的文件的最小数量。也就是说,在至少有 journal-compact-min-files 前,压缩算法不会启动。默认值为 10。把它设置为 0 可禁用压缩,因为日志可能会无限期地增加。
    2
    日志文件中实时数据的百分比。如果小于这个百分比,则压缩开始。请记住,在日志中至少具有 journal-compact-min-files 数据文件后,压缩不会开始。默认值为 30
使用 CLI 完成日志

您还可以使用命令行界面(CLI)来紧凑日志。

步骤

  1. 作为 BROKER_INSTANCE_DIR 的所有者,停止代理。在以下示例中,用户 amq-broker 是在安装 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.2.5. 禁用磁盘 Write 缓存

大多数磁盘包含硬件写缓存。写入缓存可提高磁盘的表面性能,因为写入稍后被写入磁盘。默认情况下,许多系统都启用了磁盘写缓存。这意味着,即使在从操作系统进行同步之后,也无法保证数据实际上已提供给磁盘,因此当发生故障时,关键数据可能会丢失。

有些更昂贵的磁盘具有非易失性或支持的写入缓存,这些缓存不一定会在失败时丢失数据,但您应该测试它们。如果您的磁盘没有这样的功能,您应该确定禁用写入缓存。请注意,禁用磁盘写缓存可能会对性能造成负面影响。

步骤

  • 在 Linux 上,使用工具 hdparm (用于 IDE 磁盘)或 sginfo (用于 SDSI/SATA 磁盘)来管理磁盘的写入缓存设置。
  • 在 Windows 上,通过右键单击磁盘并单击 属性 来管理缓存设置。

6.3. 配置 JDBC 持久性

JDBC 持久性存储使用 JDBC 连接在数据库表中存储消息和绑定数据。表中的数据使用 AMQ Broker 日志编码。有关支持的数据库的详情,请查看红帽客户门户网站中的 Red Hat AMQ 7 支持的配置

注意

管理员可以根据组织的更广泛的 IT 基础架构要求,将消息传递数据存储在数据库中。但是,使用数据库可能会对消息传递系统的性能造成负面影响。具体来说,通过 JDBC 将消息传递数据写入数据库表,可为代理带来显著的性能开销。

步骤

  1. 将适当的 JDBC 客户端库添加到代理运行时。您可以将相关的 jar 添加到 BROKER_INSTANCE_DIR/lib 目录中。
  2. BROKER_INSTANCE_DIR/etc/broker.xml 配置文件中创建 storage 元素,如下例所示。

    <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>BINDINGS_TABLE</bindings-table-name>
              <message-table-name>MESSAGE_TABLE</message-table-name>
              <large-message-table-name>LARGE_MESSAGES_TABLE</large-message-table-name>
              <page-store-table-name>PAGE_STORE_TABLE</page-store-table-name>
              <node-manager-store-table-name>NODE_MANAGER_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
    存在大量消息和相关数据的表的名称。另外,如果客户端在块中流 a大消息,则块会存储在这个表中。指定此表名称可让您在多个服务器之间共享单个数据库,而不会干扰。
    page-store-table-name
    存储目录信息的表的名称。指定此表名称可让您在多个服务器之间共享单个数据库,而不会干扰。
    node-manager-store-table-name
    共享存储高可用性(HA)锁定实时和备份代理的表的名称以及其他与 HA 相关的数据存储在代理服务器上。指定此表名称可让您在多个服务器之间共享单个数据库,而不会干扰。使用共享存储 HA 的每个实时备份对必须使用相同的表名称。您不能在多个(和不相关的)实时备份对之间共享相同的表。
    jdbc-driver-class-name
    JDBC 数据库驱动程序的完全限定域名。有关支持的数据库的详情,请查看红帽客户门户网站中的 Red Hat AMQ 7 支持的配置
    jdbc-network-timeout
    JDBC 网络连接超时,以毫秒为单位。默认值为 20000 毫秒。当使用 JDBC 进行共享存储 HA 时,建议将超时设置为小于或等于 jdbc-lock-expiration 的值。
    jdbc-lock-renew-period
    当前 JDBC 锁定续订周期的长度(以毫秒为单位)。当这段时间过时,代理可以续订锁定。默认值为 2000 毫秒。
    jdbc-lock-expiration
    毫秒内,当前的 JDBC 锁定被视为已激活,即使 jdbc-lock-renew-period 已被弃用。如果将此属性设置为大于 jdbc-lock-renew-period 的值,可确保如果锁定的代理在续订时遇到意外延迟,则不会立即丢失锁定。过期时间后,如果 JDBC 锁定未被当前拥有它的代理续订,则其他代理可以建立 JDBC 锁定。默认值为 20000 毫秒。
    jdbc-journal-sync-period
    持续时间(以毫秒为单位),代理日志与 JDBC 同步。默认值为 5 毫秒。

6.4. 配置 Zero Persistence

在某些情况下,在消息传递系统有时需要零持久性。将代理配置为执行零持久性非常简单。将 BROKER_INSTANCE_DIR/etc/broker.xml 中的参数 持久性 设置为 false

请注意,如果您将此参数设置为 false,则会出现 持久性。这意味着没有绑定数据、消息数据、大消息数据、重复的 ID 缓存或分页数据会被保留。

第 7 章 分页消息

AMQ Broker 透明地支持在服务器运行时包含数以百万条信息的大型队列,但内存有限。

在这种情况下,无法在任何时间点上将所有队列存储在内存中,因此 AMQ Broker 会根据需要透明地 页面 消息和内存不足,从而允许大量队列占用内存。

逐个地址进行分页。当地址中所有消息的大小超过配置的最大值时,AMQ Broker 将开始向磁盘分页信息。有关地址的更多信息,请参阅配置地址和队列

默认情况下,AMQ Broker 不会页面信息。您必须明确配置分页才能启用它。

如需了解如何使用 AMQ Broker 的 分页 示例,请参阅 INSTALL_DIR/examples/standard/ 下的分页示例。

7.1. 关于页面文件

信息按每个地址保存在文件系统中。每个地址都有一个单独的文件夹,其中消息存储在多个文件中(页面文件)。每个文件将包含最多配置的最大大小的消息(page-size-bytes)。在需要时,系统将导航到文件,一旦所有消息被确认到该点,它将立即删除页面文件。

浏览器将通过 page-cursor 系统读取。

带有选择器的消费者还将浏览 page-files 并忽略不与条件不匹配的消息。

注意

如果您有一个队列,并且消费者使用非常严格的选择器过滤队列时,您可能会遇到一些情况,因为您无法从分页中读取更多数据,直到您消耗来自队列中的消息。

示例:在一个消费者中,使用一个选择器作为 'color="red"',但在蓝色之后只有一个颜色的红色消息,在使用蓝色前,您将无法使用红色。这与浏览不同,因为我们在提供队列时,我们将"浏览"整个队列查找信息,同时我们"页面"消息。

7.2. 配置分页目录位置

要配置分页目录的位置,请将 分页目录配置 元素添加到代理的主配置文件 BROKER_INSTANCE_DIR/etc/broker.xml,如下例所示。

<configuration ...>
  ...
  <core ...>
    <paging-directory>/somewhere/paging-directory</paging-directory>
    ...
  </core>
</configuration>

AMQ Broker 将在配置的位置为每个地址创建一个目录。

7.3. 配置用于分页的地址

在地址级别上进行分页配置,可将元素添加到特定的 address-settings 中,如下例所示。

<address-settings>
   <address-setting match="jms.paged.queue">
      <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>

在上例中,当发送到地址 jms.paged.queue 的消息在内存中超过 104857600 字节时,代理将开始分页。

注意

逐个地址进行分页。如果您为地址指定了 max-size-bytes,则每个匹配地址都不会超过您指定的最大大小。它并不意味着所有匹配地址的总大小仅限于 max-size-bytes

这是地址设置中可用参数的列表。

表 7.1. 分页配置元素

元素名称描述Default(默认)

max-size-bytes

在代理进入页面模式前,地址允许的最大内存大小。

-1(禁用)。

当禁用这个参数时,代理使用 global-max-size 作为分页的 memory-usage 限制。如需更多信息,请参阅 第 7.4 节 “配置全局保留大小”

page-size-bytes

分页系统中使用的每个页面文件的大小。

10MiB(10 \* 1024 \* 1024 字节)

address-full-policy

有效值为 PAGEDROPBLOCKFAIL。如果值为 PAGE,则会将进一步的信息写到磁盘中。如果该值为 DROP,则其他消息将被静默丢弃。如果值为 FAIL,则消息将被丢弃,并且客户端消息制作者将收到异常。如果值为 BLOCK,则客户端消息制作者将在尝试并发送更多消息时阻止。

页面

page-max-cache-size

系统将在内存中保留这个数量的页面文件,以便在分页导航期间优化 IO。

5

page-sync-timeout

定期页面同步之间的时间(以纳秒为单位)。

如果您使用异步 IO 日志(即,log -typebroker.xml 配置文件中设置为 ASYNCIO ),则默认值为 3333333 nanoseconds(即 3.333333 毫秒)。如果您使用标准 Java NIO 日志(即,log-type 设为 NIO),则默认值为 journal-buffer-timeout 参数的值。

7.4. 配置全局保留大小

有时每个地址配置内存限值并不实际,比如当代理管理许多具有不同使用模式的地址时。在这些情况下,使用 global-max-size 参数将全局限制设置为代理在进入与传入信息关联的地址的页模式前可以使用的限值。

global-max-size 的默认值是 Java 虚拟机(JVM)可用的最大内存的一半。您可以通过在 broker.xml 配置文件中进行配置,为这个参数指定自己的值。global-max-size 的值以字节为单位,但您可以使用字节表示法("K", "Mb", "GB",例如 )。

以下流程演示了如何在 broker.xml 配置文件中配置 global-max-size 参数。

配置 global-max-size 参数

步骤

  1. 停止代理。

    1. 如果代理在 Linux 上运行,请运行以下命令:

      BROKER_INSTANCE_DIR/bin/artemis stop
    2. 如果代理在 Windows 上作为服务运行,请运行以下命令:

      BROKER_INSTANCE_DIR\bin\artemis-service.exe stop
  2. 打开位于 BROKER_INSTANCE_DIR 下的 broker.xml 配置文件。
  3. global-max-size 参数添加到 broker.xml 以限制其内存大小(以字节为单位),代理可以使用。请注意,您也可以使用字节符号(KMbGB)作为 global-max-size 的值,如下例所示。

    <configuration>
      <core>
        ...
        <global-max-size>1GB</global-max-size>
        ...
      </core>
    </configuration>

    在前面的示例中,代理被配置为在处理消息时,最多使用 1GB 字节、1GB 可用内存。如果超过配置的限制,代理会进入与传入消息关联的地址配置页面模式。

  4. 启动代理。

    1. 如果代理在 Linux 上运行,请运行以下命令:

      BROKER_INSTANCE_DIR/bin/artemis run
    2. 如果代理在 Windows 上作为服务运行,请运行以下命令:

      BROKER_INSTANCE_DIR\bin\artemis-service.exe start

相关信息

有关为地址设置分页模式的信息,请参阅 第 7.3 节 “配置用于分页的地址”

7.5. 在 Paging 时限制磁盘用量

您可以在块传入的消息前限制代理使用的物理磁盘量,而不是分页它们。将 max-disk-usage 添加到 broker.xml 配置文件,并为分页消息时代理可以使用的磁盘空间百分比提供一个值。max-disk-usage 的默认值为 90 ,这意味着限制在磁盘空间的 90% 设定。

配置 max-disk-usage

步骤

  1. 停止代理。

    1. 如果代理在 Linux 上运行,请运行以下命令:

      BROKER_INSTANCE_DIR/bin/artemis stop
    2. 如果代理在 Windows 上作为服务运行,请运行以下命令:

      BROKER_INSTANCE_DIR\bin\artemis-service.exe stop
  2. 打开位于 BROKER_INSTANCE_DIR 下的 broker.xml 配置文件。
  3. 添加 max-disk-usage 配置元素,并将限制设置为在分页信息时要使用的磁盘空间量。

    <configuration>
      <core>
        ...
        <max-disk-usage>50</max-disk-usage>
        ...
      </core>
    </configuration>

    在前面的示例中,代理在分页消息时限制为使用 50% 的磁盘空间。消息会被阻止,在使用磁盘 50% 后不再进行分页。

  4. 启动代理。

    1. 如果代理在 Linux 上运行,请运行以下命令:

      BROKER_INSTANCE_DIR/bin/artemis run
    2. 如果代理在 Windows 上作为服务运行,请运行以下命令:

      BROKER_INSTANCE_DIR\bin\artemis-service.exe start

7.6. 如何 Drop Messages

在达到最大大小时,地址也可以配置为仅丢弃地址信息,而不是在达到最大大小时分页信息。

为此,在地址设置中将 address-full-policy 设置为 DROP

7.6.1. 为 Producers 丢弃消息和把一个例外

在达到最大大小时,地址也可以配置为丢弃信息,并在地址满时在客户端上抛出异常。

为此,在地址设置中将 address-full-policy 设置为 FAIL

7.7. 如何块生产器

在达到 max 大小时,地址也可以配置为阻止生产者在地址满时发送更多消息,从而防止内存在服务器中被耗尽,而不是分页消息。

注意

仅在使用协议时阻断可以正常工作。例如,AMQP 制作者将在代理发送时理解 Block 数据包,但 STOMP 生产器将不会。

当内存在服务器上释放时,生产者会自动取消块,并且能够继续发送。

为此,可在地址设置中将 address-full-policy 设置为 BLOCK

在默认配置中,所有地址都配置为在地址 10 MiB 后阻止制作者。

7.8. 使用多播队列的地址非常谨慎

当消息路由到绑定到该地址的多播队列时,例如在主题中的 JMS 订阅,内存中只有一条消息副本。每个队列仅处理对其的引用。由于此内存仅在引用消息的所有队列都已发送后释放。

如果您有单个延迟订阅,则整个地址将遭遇 IO 性能,因为所有队列都将通过分页系统上的额外存储来发送消息。

例如:

  • 地址有 10 个队列
  • 其中一个队列无法提供其消息(因为消费者速度过慢)。
  • 消息持续到达地址并启动分页。
  • 即使已经发送了消息,其他 9 个队列就为空。

在这个示例中,所有其他 9 队列将消耗来自页面系统的消息。如果这是不良状态,这可能会导致性能问题。

第 8 章 处理大量消息

客户端可能会发送超过代理内部缓冲大小的大信息,从而导致意外错误。要防止这种情况,您可以将代理配置为在消息大于指定最小值时存储消息。以这种方式处理大量消息意味着代理不会在内存中保存消息。相反,您可以在磁盘或数据库表中指定代理存储大量消息文件的目录。

当代理将消息作为大消息存储时,队列会保留对大型消息目录或数据库表中的文件的引用。

核心协议、AMQP、OpenWire 和 STOMP 协议提供了大型消息处理。

对于 Core Protocol 和 OpenWire 协议,客户端在其连接配置中指定最小大消息大小。对于 AMQP 和 STOMP 协议,您可以在代理配置中为每个协议定义接受者中指定最小大消息大小。

注意

建议您 不要将 不同的协议用于生成和消耗大型消息。要做到这一点,代理可能需要执行多个消息转换。例如,假设您要使用 AMQP 协议发送消息并使用 OpenWire 接收它。在这种情况下,代理必须首先读取大量消息的整个正文,并将其转换为使用内核协议。然后,代理必须执行另一个转换,此时到 OpenWire 协议。诸如此类的消息转换会导致代理上的大量处理开销。

您为上述任何协议指定的大型消息大小将受到系统资源(如可用磁盘空间量)以及消息的大小的影响。建议您使用多个值运行性能测试来确定适当的大小。

本节中的步骤演示了如何:

  • 配置代理以存储大型信息
  • 为大型消息处理配置 AMQP 和 STOMP 协议的接收器

本节还链接到用于配置 AMQ Core Protocol 和 AMQ OpenWire JMS 客户端的其他资源,以处理大型消息。

8.1. 为大型消息处理配置代理

以下流程演示了如何指定磁盘或者数据库表中的目录,该表会存储大量消息文件。

步骤

  1. 打开 <broker-instance-dir>/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. 打开 <broker-instance-dir>/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 接受器(或您配置的另一个 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 的值,如果接受者收到大于或等于 204800 字节的 AMQP 消息(即 200 KB),代理将消息保存为大消息。如果您没有为此属性显式指定值,代理会使用默认值 102400(即 100 KB)。

注意
  • 如果将mq pMinLargeMessageSize 设置为 -1,则禁用用于 AMQP 消息的大型消息处理。
  • 如果代理收到未超过mqp MinLargeMessageSize 的值的持久 AMQP 消息,但该消息超过了消息传递日志缓冲区的大小(使用 journal-buffer-size 配置参数指定),代理会将消息转换为大型 Core Protocol 消息,然后再将其保存到日志中。

8.3. 为大型消息处理配置 STOMP 接受器

以下流程演示了如何配置 STOMP acceptor 来处理大于指定大小的 STOMP 消息作为大消息。

步骤

  1. 打开 <broker-instance-dir>/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 acceptor)中,添加 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 的值,如果接受者收到 STOMP 消息,其正文大于大于 204800 字节(即 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
连接实例化的客户端代码中的 行。

从客户端初始化中检测没有连接

只要从代理接收数据,客户端就会认为连接处于活动状态。通过为 client- failure-check-period 属性提供一个值 来配置客户端来检查其连接失败。网络连接的默认检查周期为 30000 毫秒,而 In-VM 连接的默认值是 -1,如果未收到数据,客户端不会失败。

通常,您会将检查周期设置为低于代理连接生存时间的值,这样可确保客户端在临时失败时能够重新连接。

以下示例说明如何使用核心 JMS 客户端将检查周期设置为 10000 毫秒。

步骤

  • 设置检测不可用连接的检查周期。

    • 如果您将 JNDI 与核心 JMS 客户端搭配使用,请在 JNDI 上下文环境中设置检查周期,例如 jndi.properties,如下所示。

      java.naming.factory.initial=org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory
      connectionFactory.myConnectionFactory=tcp://localhost:61616?clientFailureCheckPeriod=10000
    • 如果您不使用 JNDI 设置检查周期,将值传递给 ActiveMQConnectionFactory.setClientFailureCheckPeriod()

      ConnectionFactory cf =  ActiveMQJMSClient.createConnectionFactory(...)
      cf.setClientFailureCheckPeriod(10000);

9.1. 连接 Time-To-Live

因为客户端和服务器间的网络连接可能会失败,然后返回在线,因此允许客户端重新连接,AMQ Broker 会等待清理不活跃的服务器端资源。此等待时间称为生存时间(TTL)。基于网络的连接的默认 TTL 是 60000 毫秒(1 分钟)。In-VM 连接的默认 TTL 是 -1,这意味着代理永远不会超时。

在 Broker 中配置 Time-To-Live

如果您不希望客户端指定自己的连接 TTL,您可以在代理端设置全局值。这可以通过在代理配置中指定 connection-ttl-override 元素来实现。

检查 TTL 冲突连接的逻辑定期在代理上运行,具体由 connection-ttl-check-interval 元素决定。

步骤

  • 通过添加 connection-ttl-override 配置元素并为生存时间提供值,编辑 BROKER_INSTANCE_DIR/etc/broker.xml,如下例所示。

    <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 毫秒完成一次。

在客户端上配置 Time-To-Live

默认情况下,客户端可以为自己的连接设置 TTL。以下示例演示了如何使用核心 JMS 客户端设置 Time-To-Live。

步骤

  • 为客户端连接设置 Time-To-Live。

    • 如果您使用 JNDI 来实例化连接工厂,您可以使用 参数 connectionTTL 在 xml 配置中指定。

      java.naming.factory.initial=org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory
      connectionFactory.myConnectionFactory=tcp://localhost:61616?connectionTTL=30000
    • 如果您不使用 JNDI,则连接 TTL 由 ActiveMQConnectionFactory 实例上的 ConnectionTTL 属性来定义。

      ConnectionFactory cf =  ActiveMQJMSClient.createConnectionFactory(...)
      cf.setConnectionTTL(30000);

9.2. 禁用异步连接执行

代理一侧接收的大部分数据包都在删除线程中 执行。这些数据包代表简短运行的操作,并且始终在远程线程中执行,以提高性能。但是,一些数据包类型是使用线程池而不是删除线程来执行,这会增加一些网络延迟。

使用以下列出的 Java 类中实施使用线程池的数据包类型。课程都在软件包 org.apache.actiinvemq.artemis.core.protocol.core.impl.wireformat 中找到。

  • RollbackMessage
  • SessionCloseMessage
  • SessionCommitMessage
  • SessionXACommitMessage
  • SessionXAPrepareMessage
  • SessionXARollbackMessage

步骤

  • 要禁用异步连接执行,请将支持 async-connection-execution-enabled 配置元素添加到 BROKER_INSTANCE_DIR/etc/broker.xml,并将它设置为 false,如下例所示。默认值为 true

    <configuration>
     <core>
      ...
      <async-connection-execution-enabled>false</async-connection-execution-enabled>
      ...
     </core>
    </configuration>

9.3. 关闭客户端连接

客户端应用程序必须在退出前以受控的方式关闭其资源,以防止发生死连接。在 Java 中,建议关闭 最终 块中的连接:

Connection jmsConnection = null;
try {
   ConnectionFactory jmsConnectionFactory = ActiveMQJMSClient.createConnectionFactoryWithoutHA(...);
   jmsConnection = jmsConnectionFactory.createConnection();
   ...use the connection...
}
finally {
   if (jmsConnection != null) {
      jmsConnection.close();
   }
}

第 10 章 流控制

通过限制它们间的数据流,流程控制可以防止生产者和使用者变得超值。通过使用 AMQ Broker,您可以为使用者和生产器配置流控制。

10.1. 消费者流控制

消费者流控制规定了代理和客户端之间的数据流,因为客户端会消耗来自代理的消息。默认情况下,AMQ Broker 客户端缓冲消息在向消费者交付前。如果没有缓冲,客户端首先需要请求来自代理的每个信息,然后再使用它。这种类型的"往返"通信非常昂贵。在客户端上监管数据流非常重要,因为内存不足问题可能会导致使用者无法快速处理消息,并且缓冲区开始与传入消息溢出。

10.1.1. 设置 Consumer Window 大小

客户端缓冲区中操作的最大消息大小由其 窗口大小 决定。AMQ Broker 客户端窗口的默认大小为 1 MiB,或 1024 * 1024 字节。对于大多数用例来说,默认设置非常正常。对于其他情况,找到窗口大小的最佳值可能需要对系统进行基准测试。如果需要更改默认,AMQ Broker 允许您设置缓冲区窗口大小。

设置窗口大小

以下示例演示了如何在使用 Core JMS 客户端时设置使用者窗口大小参数。每个示例将消费者窗口大小设置为 300000 字节。

步骤

  • 设置使用者窗口大小。

    • 如果核心 JMS 客户端使用 JNDI 来实例化其连接工厂,则将 consumerWindowSize 参数包含为连接字符串 URL 的一部分。将 URL 存储在 JNDI 上下文环境中。以下示例使用 jndi.properties 文件来存储 URL。

      java.naming.factory.initial=org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory
      connectionFactory.myConnectionFactory=tcp://localhost:61616?consumerWindowSize=300000
    • 如果核心 JMS 客户端不使用 JNDI 来实例化其连接工厂,请将值传递给 ActiveMQConnectionFactory.setConsumerWindowSize()

      ConnectionFactory cf =  ActiveMQJMSClient.createConnectionFactory(...)
      cf.setConsumerWindowSize(300000);

10.1.2. 处理 Fast Consumers

快速消费者可以像使用时快速处理消息。如果您确信消息传递系统中的使用者速度很快,请考虑将窗口大小设置为 -1。此设置允许在客户端端绑定消息缓冲。但要谨慎使用此设置。如果使用者无法像收到消息一样,它能够使客户端一侧内存处理速度。

为 Fast Consumers 设置窗口大小

步骤

以下示例说明了如何在使用快速消息使用者的 Core JMS 客户端时,如何将窗口大小设置为 -1

  • 将使用者窗口大小设置为 -1

    • 如果核心 JMS 客户端使用 JNDI 来实例化其连接工厂,则将 consumerWindowSize 参数包含为连接字符串 URL 的一部分。将 URL 存储在 JNDI 上下文环境中。以下示例使用 jndi.properties 文件来存储 URL。

      java.naming.factory.initial=org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory
      connectionFactory.myConnectionFactory=tcp://localhost:61616?consumerWindowSize=-1
    • 如果核心 JMS 客户端不使用 JNDI 来实例化其连接工厂,请将值传递给 ActiveMQConnectionFactory.setConsumerWindowSize()

      ConnectionFactory cf =  ActiveMQJMSClient.createConnectionFactory(...)
      cf.setConsumerWindowSize(-1);

10.1.3. 处理较低消费者

缓慢的消费者需要花费大量时间来处理每条信息。在这些情况下,建议不要在客户端一侧缓冲信息。相反,消息仍保留在代理端,以供其他消费者使用。关闭缓冲区的一个好处是它在队列中的多个消费者之间提供确定的分布。要通过禁用客户端缓冲区来处理较慢的用户,请将窗口大小设置为 0。

为 Slow Consumers 设置窗口大小

步骤

以下示例显示,在使用 Core JMS 客户端时,如何将窗口大小设置为 0, 而这个客户端是速度较慢的消息。

  • 将使用者窗口大小设置为 0。

    • 如果核心 JMS 客户端使用 JNDI 来实例化其连接工厂,则将 consumerWindowSize 参数包含为连接字符串 URL 的一部分。将 URL 存储在 JNDI 上下文环境中。以下示例使用 jndi.properties 文件来存储 URL。

      java.naming.factory.initial=org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory
      connectionFactory.myConnectionFactory=tcp://localhost:61616?consumerWindowSize=0
    • 如果核心 JMS 客户端不使用 JNDI 来实例化其连接工厂,请将值传递给 ActiveMQConnectionFactory.setConsumerWindowSize()

      ConnectionFactory cf =  ActiveMQJMSClient.createConnectionFactory(...)
      cf.setConsumerWindowSize(0);

相关信息

请参阅示例 no-consumer-buffering in INSTALL_DIR/examples/ standard 以了解一个示例,它演示了如何配置代理以防止处理速度较慢的用户时的消费者缓冲。

10.1.4. 设置截止消息的比率

您可以规定消费者可以使用消息的速率。也称为 "throttling",对消耗率进行限制,可确保消费者不会消耗比配置允许的速度快的消息。

注意

速率限制流控制可与基于窗口的流控制一起使用。速率限制流控制只会影响客户端可以消耗的每秒消息数量,而不影响其缓冲区中有多少消息。随着速率的速率限制和高窗口的限制,客户端的内部缓冲区会快速使用消息进行填充。

速率必须是正整数,才能启用这个功能,它是每秒以消息单位指定的最大消息消耗率。将速率限制设置为 -1 可禁用速率限制流控制。默认值为 -1

设置截止消息的比率

步骤

以下示例使用 Core JMS 客户端,将消耗消息速率限制为每秒 10 个消息。

  • 设置使用者率。

    • 如果核心 JMS 客户端使用 JNDI 来实例化其连接工厂,请将 consumerMaxRate 参数作为连接字符串 URL 的一部分。将 URL 存储在 JNDI 上下文环境中。以下示例使用 jndi.properties 文件来存储 URL。

      java.naming.factory.initial=org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory
      java.naming.provider.url=tcp://localhost:61616?consumerMaxRate=10
    • 如果核心 JMS 客户端不使用 JNDI 来实例化其连接工厂,请将值传递到 ActiveMQConnectionFactory.setConsumerMaxRate()

      ConnectionFactory cf =  ActiveMQJMSClient.createConnectionFactory(...)
      cf.setConsumerMaxRate(10);

相关信息

有关如何限制消费者率的工作示例,请参阅 INSTALL_DIR/examples/standard 中的 consumer-rate-limit 示例。

10.2. 制作者流控制

与消费者基于窗口的流控制类似,AMQ Broker 可以限制从制作者发送到代理的数据量,以防止代理占用太多数据。在制作者时,窗口大小决定随时可处于飞机中的字节数。

10.2.1. 设置 Producer 窗口大小

窗口大小以学分为基础在代理与制作者之间协商,窗口中的每字节一个学分。由于消息被发送并且使用信贷,生产者必须请求,并且获得代理的信贷,然后才能发送更多消息。制作者和代理间的信用交换规定了它们之间的数据流。

设置窗口大小

以下示例演示了如何在使用 Core JMS 客户端时将制作者窗口大小设置为 1024 字节。

步骤

  • 设置制作者窗口大小。

    • 如果核心 JMS 客户端使用 JNDI 来实例化其连接工厂,请将 producerWindowSize 参数包含为连接字符串 URL 的一部分。将 URL 存储在 JNDI 上下文环境中。以下示例使用 jndi.properties 文件来存储 URL。

      java.naming.factory.initial=org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory
      java.naming.provider.url=tcp://localhost:61616?producerWindowSize=1024
    • 如果核心 JMS 客户端不使用 JNDI 来实例化其连接工厂,请将值传递到 ActiveMQConnectionFactory.setProducerWindowSize()

      ConnectionFactory cf =  ActiveMQJMSClient.createConnectionFactory(...)
      cf.setProducerWindowSize(1024);

10.2.2. 阻塞消息

由于多个制作者可以和同一地址关联,因此代理可能会在所有生产者中分配比实际可用更多的信贷。但是,您可以在任何防止代理发送分数超过可用值的任何地址上设置最大值。

在默认配置中,每个地址使用全局最大 100Mb 大小。当地址已满时,代理会将进一步的信息写入分页日志,而不是将其路由到队列。您可以阻止客户端发送更多信息,而不必分页,直到您使用了旧的消息。以这种方式阻止生产者流控制,防止代理耗尽内存,因为生产者在任何一个时间点上发送多个消息。

在配置中,块制作者流控制基于每个 address-setting 进行管理。配置适用于注册到地址的所有队列。换句话说,绑定到该地址的所有队列的总内存上限为 max-size-bytes 的值。

注意

阻塞取决于协议。在 AMQ Broker 中,AMQP、OpenWire 和 CoreWire 支持生产流程控制。但是,AMQP 会以不同的方式处理流程控制。如需更多信息 ,请参阅使用 AMQP 进行传输控制。

为地址配置最大大小

要将代理配置为在最大字节数范围内阻止消息,请向 BROKER_INSTANCE_DIR /etc/broker.xml 添加新的 addres-setting 配置元素到 BROKER_INSTANCE_DIR/etc/broker.xml

步骤

  • 在下面的示例配置中,address-settings 被设置为 BLOCK producers,在达到其最大大小为 300000 字节后发送消息。
<configuration>
  <core>
    ...
    <address-settings>
       <address-setting match="my.blocking.queue"> 1
          <max-size-bytes>300000</max-size-bytes>  2
          <address-full-policy>BLOCK</address-full-policy> 3
       </address-setting>
    </address-settings>
  </core>
</configuration>
1
以上配置适用于由 my.blocking.queue 地址()引用的任何队列。
2
将最大大小设置为 300000 字节。如果消息超过 max-size-bytes,代理将阻止从发送到地址的制作者。请注意,此元素支持字节表示法,如 "K"、"Mb" 和 "GB"。
3
address-full-policy 设置为 BLOCK,以启用阻塞制作者流控制。

10.2.3. 阻塞 AMQP 消息

如本章前文中所述,核心协议使用制作器窗口大小流控制系统。在此系统中,学分代表字节数,并分配到制作者。如果制作者想要发送消息,则必须等到它有充足的得分,以适应消息的大小,然后再发送消息。

但是,AMQP 流控制学分不是字节的代表,而是代表制作者被允许发送的消息数量,而不考虑消息大小。因此,在一些情况下,AMQP 客户端会显著超过地址的 max-size-bytes

要管理此情况,请将元素 max-size-bytes-reject-threshold 添加到 address-setting 中,以指定地址大小(以字节为单位)的上限。达到这个上限后,代理将拒绝 AMQP 消息。默认情况下,max-size-bytes-reject-threshold 设置为 -1,或者没有限制。

将 Broker 配置为块 AMQP 消息

要将代理配置为在最大字节数范围内阻止 AMQP 消息,请将一个新的 addres-setting 配置元素添加到 BROKER_INSTANCE_DIR/etc/broker.xml

步骤

  • 以下示例配置将最大大小为 300000 字节应用到路由到 my.amqp.blocking.queue 地址的任何 AMQP 消息。

    <configuration>
      <core>
        ...
        <address-settings>
           ...
           <address-setting match="my.amqp.blocking.queue"> 1
              <max-size-bytes-reject-threshold>300000</max-size-bytes-reject-threshold>  2
           </address-setting>
        </address-settings>
      </core>
    </configuration>
1
以上配置适用于由 my.amqp.blocking.queue 地址引用的任何队列。
2
代理配置为拒绝发送到与此地址匹配的队列的 AMQP 消息,如果它们大于 max-size-bytes-reject-threshold300000 字节。请注意,这个元素 不支持 字节表示法,如 KMb、和 GB

附加资源

10.2.4. 设置发送消息率

AMQ Broker 也可以限制制作者可以发出消息的速度。制作者率以每秒消息单位指定。将它设置为 -1(默认值)禁用速率限制流控制。

设置发送消息率

以下示例演示了如何在制作者使用核心 JMS 客户端时设置发送消息的速度。每个示例将消息每秒发送到 10 的最大值。

步骤

  • 设置制作者可以发送消息的速率。

    • 如果核心 JMS 客户端使用 JNDI 来实例化其连接工厂,请将 producerMaxRate 参数包含为连接字符串 URL 的一部分。将 URL 存储在 JNDI 上下文环境中。以下示例使用 jndi.properties 文件来存储 URL。

      java.naming.factory.initial=org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory
      java.naming.provider.url=tcp://localhost:61616?producerMaxRate=10
    • 如果核心 JMS 客户端不使用 JNDI 来实例化其连接工厂,请将值传递到 ActiveMQConnectionFactory.setProducerMaxRate()

      ConnectionFactory cf =  ActiveMQJMSClient.createConnectionFactory(...)
      cf.setProducerMaxRate(10);

相关信息

如需了解如何限制发送消息的频率,请参阅 INSTALL_DIR/examples/standard 中的 制作者-rate-limit 示例。

第 11 章 消息组

消息组是有以下特征的一组消息:

  • 消息组中的消息共享相同的组 ID,即它们具有相同的组标识符属性。对于 JMS 消息,属性是 JMSXGroupID
  • 消息组中的消息始终由同一消费者使用,即使队列中有多个使用者也是如此。如果原始消费者关闭,选择另一消费者接收消息组。

当您希望对某个属性值的所有消息由同一消费者按顺序处理时,消息组很有用。例如,您可能希望订购任何特定的库存购买,以便由相同的消费者按顺序处理。为此,您可以创建使用者池,然后将库存名称设置为 message 属性的值。这样可确保特定库存的所有消息始终由同一消费者处理。

注意

分组的消息可能会影响队列的底层 FIFO 语义的并发处理非组消息。例如,如果队列头有 100 个组消息的块,并且后接 1,000 个非组消息,则所有分组的消息都将发送到适当的客户端,然后再使用任何非组的消息。这种情况下的功能影响是并发消息处理的临时挂起,同时处理所有分组的消息。在确定您的消息组大小时,请记住这种潜在的性能瓶颈。考虑是否要将分组的消息与您的非组消息隔离。

11.1. 客户端消息组

以下示例演示了如何使用核心 JMS 客户端的消息分组。

步骤

  • 设置组 ID。

    • 如果您使用 JNDI 为 JMS 客户端建立 JMS 连接工厂,请添加 groupID 参数并提供一个值。使用此连接工厂发送的所有消息都将属性 JMSXGroupID 设置为指定的值。

      java.naming.factory.initial=org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory
      connectionFactory.myConnectionFactory=tcp://localhost:61616?groupID=MyGroup
    • 如果您不使用 JNDI,请使用 setStringProperty() 方法设置 JMSXGroupID 属性。

       Message message = new TextMessage();
       message.setStringProperty("JMSXGroupID", "MyGroup");
       producer.send(message);

相关信息

请参阅 INSTALL_DIR/examples/features/standard 下的 mesagge-groupmessage-group2,以了解如何配置和使用消息组的示例。

11.2. 自动消息分组

您可以通过自动生成 ID,而不是自己提供组 ID。以这种方式分组的消息仍然由一个消费者按顺序处理。

步骤

以下示例演示了如何使用核心 JMS 客户端启用消息分组。

  • 启用自动生成组 ID。

    • 如果您使用 JNDI 上下文环境来实例化 JMS 连接工厂,请将 autogroup=true name-value 对添加到连接 URL 的查询字符串中。

      java.naming.factory.initial=org.apache.activemq.artemis.jndi.ActiveMQInitialContextFactory
      connectionFactory.myConnectionFactory=tcp://localhost:61616?autoGroup=true
    • 如果您不使用 JNDI,请在 ActiveMQConnectonFactory 上将 autogroup 设为 true

      ActiveMQConnectionFactory cf = ActiveMQJMSClient.createConnectionFactoryWithoutHA(...);
      cf.setAutoGroup(true);

第 12 章 重复消息检测

AMQ Broker 包括自动重复消息检测,它会过滤接收的任何重复消息,因此您不必对您自己的重复检测逻辑进行编码。

如果没有重复检测,客户端将无法决定在目标代理或连接它的连接失败时它发送的消息是否成功。例如,如果在接收和代理处理消息 代理或连接失败,则消息不会到达其地址,并且客户端不会因为失败而从代理接收响应。另一方面,如果在收到信息并处理了代理后代理或连接失败,则消息会被正确路由,但客户端仍然不会收到响应。

此外,使用事务来确定成功不适用于这些情况。如果在处理事务提交时代理或连接失败,例如,客户端仍然可以确定它是否已成功发送。

如果客户端重新发送最后一条消息以更正假定的失败,则结果可能是发送到地址的重复消息,这可能会给您的系统造成负面影响。发送重复消息可能意味着购买订单要满足两次,例如:幸运的是,{AMQ Broker} 提供自动重复的信息检测,以防止此类问题发生。

12.1. 使用 Duplicate ID Message Property

要启用重复消息检测,请为消息属性 _AMQ_DUPL_ID 提供唯一值。当代理收到信息时,它会检查 _AMQ_DUPL_ID 是否有值。如果存在,代理则会检查其内存缓存中,以查看它是否已收到了具有该值的消息。如果找到了具有相同值的消息,则忽略传入的消息。

步骤

以下示例演示了如何使用核心 JMS 客户端设置重复检测属性。请注意,为方便起见,客户端使用恒定的 org.apache.activemq.artemis.api.core.Message.HDR_DUPLICATE_DETECTION_ID 作为重复 ID 属性的名称 _AMQ_DUPL_ID

  • _AMQ_DUPL_ID 的值设置为一个唯一的 String

    Message jmsMessage = session.createMessage();
    String myUniqueID = "This is my unique id";
    message.setStringProperty(HDR_DUPLICATE_DETECTION_ID.toString(), myUniqueID);

12.2. 配置重复 ID 缓存

代理维护接收值的缓存,即 _AMQ_DUPL_ID 属性。每个地址都有自己的不同的缓存。缓存是圆形的,固定。新条目会取代最旧的缓存空间需求。

注意

确保适当地调整缓存大小。如果之前的消息到达超过 id-cache-size 的信息,则代理无法检测到重复信息。这会导致代理处理这两个消息。

步骤

以下示例配置说明了如何通过向 BROKER_INSTANCE_DIR/etc/broker.xml 添加元素来配置 ID 缓存。

<configuration>
  <core>
    ...
    <id-cache-size>5000</id-cache-size> 1
    <persist-id-cache>false</persist-id-cache> 2
  </core>
</configuration>
1
缓存的最大大小由参数 id-cache-size 配置。默认值为 20000 条目。在上例中,缓存大小设置为 5000 条目。
2
persist-id-cache 设置为 true 时,每个 ID 都会在接收时保存在磁盘中。默认值为 true。在上例中,通过将值设为 false 来禁用持久性。

12.3. 重复检测和事务

使用重复检测在代理之间移动消息可以为您提供一次相同,且只有经过一次发送保证您使用 XA 事务来消耗消息,但消耗比使用 XA 更容易的配置。

如果要在事务中发送消息,则不必为事务中的每条消息设置 _AMQ_DUPL_ID,但仅在其中一个消息中设置 _AMQ_DUPL_ID。如果代理检测到事务中任何消息的重复信息,它会忽略整个事务。

12.4. 重复检测和集群连接

您可以配置集群连接,为它们在集群中移动的每个消息插入重复 ID。

步骤

  • 将元素 use-duplicate-detection 添加到 BROKER_INSTANCE_DIR/etc/broker.xml 中的所需集群连接的配置。请注意,这个参数的默认值是 true。在以下示例中,元素添加到集群连接 my-cluster 的配置中。

    <configuration>
      <core>
        ...
        <cluster-connection>
           <cluster-connection name="my-cluster">
             <use-duplicate-detection>true</use-duplicate-detection>
             ...
           </cluster-connection>
           ...
        </cluster-connections>
      </core>
    </configuration>

其他资源

第 13 章 截获消息

使用 AMQ Broker,您可以截获进入或退出代理的数据包,以便您审核数据包或过滤信息。拦截器可能会更改它们拦截的数据包,这使得它们的功能强大,但也存在存在危险性。

您可以开发拦截器来满足您的业务需求。拦截器是特定于协议的,必须实现适当的接口。

拦截器必须实现 intercept() 方法,它会返回一个布尔值。如果值为 true,则消息数据包继续开启。如果为 false,则进程被中止,没有调用其他拦截器,也不会进一步处理消息数据包。

13.1. 创建拦截器

您可以创建自己的传入和传出拦截器。所有拦截器都是特定于协议的,用于分别进入或退出服务器的任何数据包调用。这可让您创建拦截器来满足业务要求,如审计数据包。拦截器可以更改它们所截获的数据包。这使得它们的功能强大且潜在的危险,因此请务必谨慎使用。

拦截器及其依赖项必须放在代理的 Java 类路径中。您可以使用 BROKER_INSTANCE_DIR/lib 目录,因为它是类路径的一部分。

步骤

以下示例演示了如何创建拦截器来检查传递给它的每个数据包的大小。请注意,示例为每个协议实施特定的接口。

  • 实施适当的接口并覆盖其拦截器 () 方法。

    • 如果您使用 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;
        }
      }
    • 如果使用 Core Protocol,您的拦截器必须实施 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;
        }
      }
    • 如果您使用 MQTT 协议,则实施 org.apache.activemq.artemis.core.protocol.mqtt.MQTTInterceptor 接口。

      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.core.protocol.stomp.StompFrameInterceptor 接口。

      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;
        }
      }

13.2. 将 Broker 配置为使用拦截器

创建拦截器后,您必须将代理配置为使用它。

先决条件

您必须创建一个拦截器类,并将其添加到代理的 Java 类路径中,然后才能将它配置为使用代理。您可以使用 BROKER_INSTANCE_DIR/lib 目录,因为它是类路径的一部分。

步骤

  • 将代理配置为在 BROKER_INSTANCE_DIR/etc/broker.xml中添加配置来使用拦截器

    • 如果您的拦截器用于传入消息,将其 类名称 添加到删除拦截器列表中。

      <configuration>
        <core>
          ...
          <remoting-incoming-interceptors>
             <class-name>org.example.MyIncomingInterceptor</class-name>
          </remoting-incoming-interceptors>
          ...
        </core>
      </configuration>
    • 如果您的拦截器用于传出消息,将其 类名称 添加到 删除 拦截器列表中。

      <configuration>
        <core>
          ...
          <remoting-outgoing-interceptors>
             <class-name>org.example.MyOutgoingInterceptor</class-name>
          </remoting-outgoing-interceptors>
        </core>
      </configuration>

13.3. 客户端侧的拦截器

客户端可以使用拦截器拦截客户端发送到服务器的数据包,或者被服务器发送到客户端。如同代理侧拦截器一样,如果返回 false,则不会调用其他拦截器,客户端也不会进一步处理数据包。除以 阻塞 方式发送传出数据包时,这个进程才会透明地对客户端发生。在这些情况下,ActiveMQException 将丢弃给调用者,因为块发送提供了可靠性。ActiveMQException thrown 包含返回假的拦截器的名称。

作为服务器上,客户端拦截器类及其依赖项必须添加到客户端的 Java 类路径中,以正确地实例化和调用。

第 14 章 隔离消息和分割消息流

在 AMQ Broker 中,您可以配置名为 move rts 的对象,以便以透明的方式将信息从一个地址移动到另一个地址,而无需更改任何客户端应用程序逻辑。您还可以配置 movert,将消息 的副本 转发到指定的转发地址,从而有效地分割消息流。

14.1. 消息传送如何工作

rts 可让您透明地将路由到一个地址的消息传送到某个其他地址,而不更改任何客户端应用逻辑。可将代理服务器集合视为消息的路由表类型。

另一款产品可以 独占使用,即消息将传播到指定的转发地址,而不考虑其原始地址。

movert 也可以是 排除的,即消息继续转至其原始地址,而代理会将消息的副本发送到指定的转发地址。因此,您可以使用非排除来分割消息流。例如,如果您想要单独监控发送到订单队列的每个顺序,您可以分割消息流。

当地址同时配置了独占和非排除的经销时,代理会首先处理独占的抵押。如果特定的消息已被独占出去,代理不会处理该消息的任何非排除符。在这种情况下,消息永远不会发送到原始地址。

当代理传播信息时,代理会分配新消息 ID,并将消息地址设置为新转发地址。您可以通过 _AMQ_ORIG_ADDRESS (字符串类型)和 _AMQ_ORIG_MESSAGE_ID (长类型)消息属性来检索原始消息 ID 和地址值。如果使用 Core API,请使用 Message.HDR_ORIGINAL_ADDRESSMessage.HDR_ORIG_MESSAGE_ID 属性。

注意

您只能将消息信息传播到同一代理服务器上的地址。如果您想移动到其他服务器上的地址,那么常见的解决方案是首先将消息移动到本地存储和转发队列。然后,设置从该队列消耗的网桥,并将消息转发到不同代理上的地址。通过将 moverts 与网桥相结合,您可以在地理上分散的代理服务器之间创建路由连接的分布式网络。这样,您可以创建全局消息传递网格。

14.2. 配置消息rts

要在代理实例中配置 movert,请在 broker.xml 配置文件的 core 元素中添加 movert 元素。

<core>
...
   <divert name= >
        <address> </address>
        <forwarding-address> </forwarding-address>
        <filter string= >
        <routing-type> </routing-type>
        <exclusive> </exclusive>
   </divert>
...
</core>
divert
转让的命名实例。只要每个 movert 具有唯一名称,就可以在 broker.xml 配置文件中添加多个 movert 元素。
address
从中 转出消息的地址
forwarding-address
要转发信息的地址
filter
可选的消息过滤器。如果您配置了过滤器,则只有与过滤器字符串匹配的消息才会被 rtrted。如果没有指定过滤器,则所有消息都将通过 movert 被视为匹配项。
routing-type

Disrted 消息的路由类型。您可以将 movert 配置为:

  • 将任何 广播多播路由 类型应用到消息
  • 删除现有 路由类型的条带(即删除)
  • 传递 (即保留)现有路由类型

当消息设置了路由类型时,路由类型的控制非常有用,但您想要将消息传播到使用不同路由类型的地址。例如,代理无法将任何广播路由类型的消息路由到使用 多播 的队列,除非将 movert 的 routing-type 参数设置为 MULTICASTmovert 的 routing-type 参数的有效值为 ANYCASTMULTICASTPASSSTRIP。默认值为 STRIP

exclusive
指定 movert 是否是独占(将 属性设置为 true)还是非专用(将属性设置为 false)。

以下小节显示了独有和非独家讲述的配置示例。

14.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 的 movert,它将发送给地址 价格更新的所有消息 移动到其他本地地址,价格转发。您还可以指定消息过滤器字符串。仅传播有消息属性 办公室 和值 New York 的消息。所有其他消息都路由到其原始地址。最后,您指定 movert 是独占的。

14.2.2. non-clusivert 示例

下面是一个非排除的 movert 的示例配置。在非独家传播信息中,一条消息会继续运行其原始地址,而代理还会将消息的副本发送到指定的转发地址。因此,非排除的 movert 是一种分割消息流的方法。

<divert name="order-divert">
   <address>orders</address>
   <forwarding-address>spyTopic</forwarding-address>
   <exclusive>false</exclusive>
</divert>

在前面的示例中,您定义一个名为 order-divert 的 movert,它将获取发送给地址 订单 的每个消息的副本并将其发送到名为 spyTopic 的本地地址。您还要指定 movert 不可排除。

其他资源

有关使用 exclusive 和 non-exclusive rts 及桥接将消息转发到另一个代理的详细示例,请参阅 Dive rt 示例 (外部)。

第 15 章 过滤消息

AMQ Broker 提供了一个强大的过滤语言,它基于 SQL 92 表达式语法的子集。过滤器语言使用的语法与用于 JMS 选择器的语法相同,但预定义的标识符不同。下表列出了适用于 AMQ Broker 消息的标识符。

标识符属性

AMQPriority

消息的优先级。消息优先级是带有有效值(从 09 )的整数。0 是最低优先级,9 为最高。

AMQExpiration

消息的过期时间。该值是一个长整数。

AMQDurable

不论消息是否持久。值是字符串。有效值为 DURABLENON_DURABLE

AMQTimestamp

创建消息的时间戳。该值是一个长整数。

AMQSize

消息的 encodeSize 属性的值。encodeSize 的值是空格,以字节为单位,消息在日志中占用。因为代理使用双字节字符集进行编码消息,因此消息的实际大小是 encodeSize 的值。

假定核心过滤器表达式中使用的任何其他标识符都是消息的属性。有关 JMS Message 的选择器语法的文档,请参阅 Java EE API

15.1. 将队列配置为使用过滤器

您可以在 BROKER_INSTANCE_DIR/etc/broker.xml 中配置的队列中添加过滤器。只有与过滤器表达式匹配的消息才会进入队列。

步骤

  • 过滤器 元素添加到所需的 队列,并将您要应用的过滤器作为元素值包括在内。在以下示例中,过滤器 NEWS='tech' 添加至队列 技术Queue 中。

    <configuration>
      <core>
        ...
        <addresses>
            <address name="myQueue">
               <anycast>
                  <queue name="myQueue">
                    <filter string="NEWS='technology'"/>
                  </queue>
               </anycast>
            </address>
         </addresses>
       </core>
    </configuration>

15.2. 过滤 JMS 消息属性

JMS 规范说明 String 属性在选择器中使用时不得转换为数字类型。例如,如果消息将 age 属性设置为 String value 21,则选择器 age > 18 不得与它匹配。此限制限制 STOMP 客户端,因为它们只能通过 String 属性发送消息。

配置过滤器以将字符串转换为数字

要将字符串属性转换为数字类型,请将 prefix convert_string_expressions: 添加到 过滤器 的值。

步骤

  • 通过将前缀 convert _string_expressions: 发送到所需的 过滤器,编辑BROKER_INSTANCE_DIR/etc/broker.xml。以下示例编辑 age > 18 的过滤器 值来 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>

15.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. 前缀,如上例中所示。

其他资源

第 16 章 设置代理集群

集群由多个代理实例组成,它们被分组在一起。代理集群通过在多个代理之间分布消息处理负载来增强性能。另外,代理集群也可以通过高可用性最小化。

您可以在许多不同的集群拓扑中连接代理。在集群中,每个活跃的代理管理自己的信息并处理自己的连接。

您还可以在集群中平衡客户端连接并重新分发消息,以避免代理丢失。

16.1. 了解代理集群

在创建代理集群前,您应该了解一些重要的集群概念。

16.1.1. 代理集群如何平衡消息负载

当代理连接到组成集群时,AMQMQ Broker 会在代理间自动平衡消息负载。这样可确保集群维护高消息吞吐量。

考虑四个代理的对称集群。每个代理都配置有名为 OrderQueue 的队列。OrderProducer 客户端连接到 Broker1,并将消息发送到 OrderQueueBroker1 以 round-robin 模式将消息转发到其他代理。连接到每个代理的 OrderConsumer 客户端会使用信息。具体顺序取决于代理启动的顺序。

图 16.1. 消息负载均衡

消息在集群中的代理中平衡负载

如果没有消息负载平衡,发送到 Broker1 的消息将保留在 Broker1,只有 OrderConsumer1 可使用它们。

虽然 AMQ Broker 会默认自动负载均衡消息,但您可以将集群配置为仅对具有匹配消费者的代理进行负载平衡的消息。您还可以将消息重新分发为没有使用者的队列自动分发消息到具有使用者的队列。

其他资源

16.1.2. 代理集群如何提高可靠性

代理集群提高了可用性和故障切换,这使得它们比独立代理更加可靠。通过配置高可用性,您可以确保客户端应用程序能够继续发送和接收消息,即使代理遇到失败事件也是如此。

借助高可用性功能,集群中的代理被分成 live-backup 组。live-backup 组包含一个提供客户端请求的 live 代理,以及在失败时等待被动替换 live 代理的一个或多个备份代理。如果发生故障,备份代理会替换其 live-backup 组中的 live 代理,客户端重新连接并继续工作。

16.1.3. 了解节点 ID

代理 节点 ID 是编程为全局唯一标识符(GUID),首次创建和初始化代理实例的日志时,生成。节点 ID 存储在 server.lock 文件中。节点 ID 用于唯一标识代理实例,无论代理是独立实例还是属于集群的一部分。live-backup 代理对共享相同的节点 ID,因为它们共享相同的日志。

在代理集群中,代理实例(节点)互相连接,并创建网桥和内部"store-and-forward"队列。这些内部队列的名称基于其他代理实例的节点 ID。代理实例还会监控与集群广播以匹配它们自己的节点 ID。如果代理识别了重复的 ID,则代理会在日志中生成警告信息。

当您使用复制高可用性(HA)策略时,启动并有 check-for-live-server 设置为 true 的 master 代理会搜索使用其节点 ID 的代理。如果 master 代理使用相同的节点 ID 找到另一个代理,它不会启动,或者根据 HA 配置启动失败。

节点 ID 是持久的,这意味着它会在代理重启后保留。但是,如果您删除代理实例(包括其日志),则也会永久删除节点 ID。

其他资源

16.1.4. 常见代理集群拓扑

您可以连接代理来形成 对称 集群拓扑。您实施的拓扑取决于您的环境和消息传递要求。

对称集群

在一个对称集群中,每个代理都连接到所有其他代理。这意味着,每个代理都没有多个与其它代理的跃点。

图 16.2. 对称集群

在每个代理都连接到所有其他代理的四对代理集群中,每个代理都连接到每个代理

对称集群中的每个代理都了解到集群中每个代理都存在的所有队列,以及侦听这些队列的用户。因此,对称集群可以比链集群更好地加载和重新分发消息。

对称集群设置比链集群更容易,但在这种环境中,网络限制会阻止代理直接连接。

链集群

在链集群中,集群中的每个代理都没有直接连接到集群中的每个代理。相反,代理会在链的每个末尾均使用代理组成链,所有其他代理都只连接到链中上一个和下一个代理。

图 16.3. 链集群

在四个代理链集群中,代理在链中连接

链集群比对称集群更容易设置,但当代理位于单独的网络且无法直接连接到时,可以使用链集群。通过使用链集群,中间代理可以间接连接两个代理,即使两个代理没有直接连接。

16.1.5. 代理发现方法

发现是指集群中代理将其连接详情相互传播的机制。AMQ Broker 支持动态发现 和静态发现

动态发现

群集中的每个代理通过 UDP 多播或 JGroups 将连接设置广播到其他成员。在此方法中,每个代理都使用:

  • 一个 广播组,用于将有关其群集连接的信息推送到集群的其他潜在成员。
  • 一个 发现组,用于接收并存储集群中其他代理的集群连接信息。
静态发现

如果您无法在网络中使用 UDP 或 JGroups,或者要手动指定集群的各个成员,您可以使用静态发现。在此方法中,通过连接到第二个代理并发送其连接详情,代理"加入"集群。然后,第二个代理将这些详情传播到集群中的其他代理。

16.1.6. 集群大小注意事项

在创建代理集群前,请考虑您的消息传递吞吐量、拓扑和高可用性要求。这些因素会影响集群中要包含的代理数量。

注意

创建集群后,您可以通过添加和删除代理来调整大小。您可以在不丢失任何信息的情况下添加和删除代理。

消息传递吞吐量

集群应该有足够的代理来提供您需要的消息吞吐量。集群中的代理数量越多,吞吐量越大。但是,大型集群可能很复杂,难以管理。

Topology

您可以创建对称集群或链集群。您选择的拓扑类型会影响可能需要的代理数量。

如需更多信息,请参阅 第 16.1.4 节 “常见代理集群拓扑”

高可用性

如果您需要高可用性(HA),请在创建集群前考虑选择 HA 策略。HA 策略会影响集群的大小,因为每个 master 代理应该至少有一个从代理。

如需更多信息,请参阅 第 16.3 节 “实施高可用性”

16.2. 创建代理集群

您可以通过在应该参与到集群的每个代理上配置集群连接来创建代理集群。集群连接定义了代理应如何连接到其他代理。

您可以创建使用静态发现或动态发现(UDP 多播或 JGroups)的代理集群。

先决条件

16.2.1. 使用静态发现创建代理集群

您可以通过指定静态代理列表来创建代理集群。如果您无法通过网络使用 UDP 多播或 JGroups,则使用此静态发现方法。

步骤

  1. 打开 <broker-instance-dir>/etc/broker.xml 配置文件。
  2. <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.2 节 “关于连接器”

  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 元素

  5. 创建集群用户和密码。

    AMQ Broker 附带默认集群凭证,但您应该更改它们以防止未授权的远程客户端使用这些默认凭证来连接代理。

    重要

    集群密码必须与集群中的每个代理相同。

    <configuration>
        <core>
            ...
            <cluster-user>cluster_user</cluster-user>
            <cluster-password>cluster_user_password</cluster-password>
            ...
        </core>
    </configuration>
  6. 在每个额外代理上重复此步骤。

    您可以将集群配置复制到每个额外代理中。但是,不要复制其他 AMQ Broker 数据文件(如绑定、日志和大型消息目录)。这些文件在集群中的节点之间必须是唯一的,否则集群无法正确表单。

其他资源

16.2.2. 使用基于 UDP 的动态发现创建代理集群

您可以创建一个代理集群,其中代理通过 UDP 多播动态发现彼此。

步骤

  1. 打开 <broker-instance-dir>/etc/broker.xml 配置文件。
  2. <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
    数据要广播的多播地址。它是一类 D IP 地址,范围为 224.0.0.0 - 239.255.255.255 (含)。地址 224.0.0.0 会被保留,不可用。这是特定于 UDP 的属性。
    group-port
    用于广播的 UDP 端口号。这是特定于 UDP 的属性。
    broadcast-period (可选)
    连续广播之间的时间间隔(以毫秒为单位)。默认值为 2000 毫秒。
    connector-ref
    之前配置的群集连接器应该被广播。
  4. 添加 UDP 发现组。

    发现组定义了此代理从其他代理接收连接器信息的方式。代理维护一个连接器列表(每个代理的一个条目)。当从代理接收广播时,它会更新其条目。如果没有从代理接收广播的时间长度,它会删除该条目。

    此发现组使用 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 属性指定发现组的唯一名称。
    local-bind-address (可选)
    如果运行代理的机器使用多个网络接口,您可以指定发现组应该侦听的网络接口。这是特定于 UDP 的属性。
    group-address
    要侦听的组的多播地址。它应当与您要侦听的广播组中的 group-address 匹配。这是特定于 UDP 的属性。
    group-port
    多播组的 UDP 端口号。它应当与您要侦听的广播组中的 group-port 匹配。这是特定于 UDP 的属性。
    refresh-timeout (可选)

    发现组在从特定代理接收最后一次广播后等待的时间(以毫秒为单位),然后再从其列表中删除代理的连接器对条目。默认值为 10000 毫秒(10 秒)。

    把它设置为比广播组的 广播期间 值高得多。否则,即使代理仍然广播(由于时间略有差异),代理可能会定期从列表中消失。

  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
    此代理用来定位集群其他成员的发现组。只有当集群使用动态发现时,才需要配置此属性。
  6. 配置集群连接的任何其他属性。

    这些额外的集群连接属性具有适用于大多数常见用例的默认值。因此,如果您不希望默认行为,您只需要配置这些属性。如需更多信息,请参阅 附录 C, Cluster Connection Configuration 元素

  7. 创建集群用户和密码。

    AMQ Broker 附带默认集群凭证,但您应该更改它们以防止未授权的远程客户端使用这些默认凭证来连接代理。

    重要

    集群密码必须与集群中的每个代理相同。

    <configuration>
        <core>
            ...
            <cluster-user>cluster_user</cluster-user>
            <cluster-password>cluster_user_password</cluster-password>
            ...
        </core>
    </configuration>
  8. 在每个额外代理上重复此步骤。

    您可以将集群配置复制到每个额外代理中。但是,不要复制其他 AMQ Broker 数据文件(如绑定、日志和大型消息目录)。这些文件在集群中的节点之间必须是唯一的,否则集群无法正确表单。

其他资源

16.2.3. 使用基于 JGroups 的动态发现创建代理集群

如果您已在环境中使用 JGroups,可以使用它来创建一个代理可以动态发现彼此的代理集群。

先决条件

步骤

  1. 打开 <broker-instance-dir>/etc/broker.xml 配置文件。
  2. <core> 元素中,添加连接器。

    此连接器定义其他代理可用于连接到此代理的连接信息。这些信息将在发现过程中发送到集群中的其他代理。

    <configuration>
        <core>
            ...
            <connectors>
                <connector name="netty-connector">tcp://localhost:61617</connector>
            </connectors>
            ...
        </core>
    </configuration>
  3. <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 通道的 JGroups 配置文件名称。该文件必须位于 Java 资源路径中,以便代理可以加载它。
    jgroups-channel
    要连接到以进行广播的 JGroups 通道的名称。
    broadcast-period (可选)
    连续广播之间的时间间隔,以毫秒为单位。默认值为 2000 毫秒。
    connector-ref
    之前配置的群集连接器应该被广播。
  4. 添加 JGroups 发现组。

    发现组定义连接器信息的方式。代理维护一个连接器列表(每个代理的一个条目)。当从代理接收广播时,它会更新其条目。如果没有从代理接收广播的时间长度,它会删除该条目。

    此发现组使用 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 属性指定发现组的唯一名称。
    jgroups-file
    用于初始化 JGroups 通道的 JGroups 配置文件名称。该文件必须位于 Java 资源路径中,以便代理可以加载它。
    jgroups-channel
    要连接的 JGroups 通道的名称,以接收广播。
    refresh-timeout (可选)

    发现组在从特定代理接收最后一次广播后等待的时间(以毫秒为单位),然后再从其列表中删除代理的连接器对条目。默认值为 10000 毫秒(10 秒)。

    把它设置为比广播组的 广播期间 值高得多。否则,即使代理仍然广播(由于时间略有差异),代理可能会定期从列表中消失。

  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
    此代理用来定位集群其他成员的发现组。只有当集群使用动态发现时,才需要配置此属性。
  6. 配置集群连接的任何其他属性。

    这些额外的集群连接属性具有适用于大多数常见用例的默认值。因此,如果您不希望默认行为,您只需要配置这些属性。如需更多信息,请参阅 附录 C, Cluster Connection Configuration 元素

  7. 创建集群用户和密码。

    AMQ Broker 附带默认集群凭证,但您应该更改它们以防止未授权的远程客户端使用这些默认凭证来连接代理。

    重要

    集群密码必须与集群中的每个代理相同。

    <configuration>
        <core>
            ...
            <cluster-user>cluster_user</cluster-user>
            <cluster-password>cluster_user_password</cluster-password>
            ...
        </core>
    </configuration>
  8. 在每个额外代理上重复此步骤。

    您可以将集群配置复制到每个额外代理中。但是,不要复制其他 AMQ Broker 数据文件(如绑定、日志和大型消息目录)。这些文件在集群中的节点之间必须是唯一的,否则集群无法正确表单。

其他资源

16.3. 实施高可用性

创建代理集群后,您可以通过实施高可用性(HA)来提高其可靠性。使用 HA 时,即使一个或多个代理离线,代理集群也可以继续正常工作。

实施 HA 涉及几个步骤:

  1. 您应该了解 live-backup 组是什么,并选择最符合您的要求的 HA 策略。请参阅 AMQ Broker 中的 HA 如何工作
  2. 当您选择了合适的 HA 策略时,请在集群中的每个代理上配置 HA 策略。请参阅:

  3. 将您的客户端应用程序配置为使用故障转移
注意

在以后的情况下,您需要对为高可用性配置的代理集群进行故障排除,建议您为集群中运行的代理(GC)实例启用 Garbage Collection(GC)日志。要了解如何在 JVM 上启用 GC 日志,请查阅您的 JVM 使用的 Java Development Kit(JDK)官方文档。有关 AMQ Broker 支持的 JVM 版本的更多信息,请参阅 Red Hat AMQ 7 支持的配置

16.3.1. 了解高可用性

在 AMQ Broker 中,您可以将集群中的代理组成 live-backup groups 来实施高可用性(HA)。在 live-backup 组中,live 代理链接到备份代理,如果无法进行实时代理,则需要接管该代理。AMQ Broker 还为 live-backup 组中的故障转移(称为 HA 策略)提供了几种不同的策略

16.3.1.1. live-backup groups 如何提供高可用性

在 AMQ Broker 中,您可以通过将集群中的代理链接到一起以形成 实时备份组 来实施高可用性(HA)。实时备份组提供 故障转移,这意味着如果一个代理失败,另一个代理可能会接管其消息处理。

live-backup 组包含一个 live 代理(有时称为 代理)组成,链接到一个或多个备份代理(有时称为 slave 代理)。live 代理提供客户端请求,而备份代理以被动模式等待。如果 live 代理失败,备份代理会替换 live 代理,使客户端重新连接并继续工作。

16.3.1.2. 高可用性策略

高可用性(HA)策略定义在 live-backup 组中如何进行故障转移。AMQ Broker 提供了几个不同的 HA 策略:

共享存储(推荐)

实时和备份代理将其消息传递数据存储在共享文件系统上的通用目录中,通常是存储区域网络(SAN)或网络文件系统(NFS)服务器。如果您配置了基于 JDBC 的持久性,您也可以将代理数据存储在指定的数据库中。使用共享存储时,如果 live 代理失败,备份代理会从共享存储中加载消息数据,并接管失败的实时代理。

在大多数情况下,您应使用共享存储而不是复制。由于共享存储不会通过网络复制数据,它通常比复制性能更好。共享存储还避免了网络隔离(也称为"脑裂")问题,其中实时代理及其备份同时处于活动状态。

在共享存储 HA 策略中,实时和备份代理都从共享位置访问日志。
复制

实时和备份代理不断通过网络同步其消息传递数据。如果 live 代理失败,备份代理会加载同步的数据,并接管失败的实时代理。

实时和备份代理之间的数据同步可确保当实时代理失败时不会丢失任何消息传递数据。当实时和备份代理首次加入时,实时代理通过网络将所有现有数据复制到备份代理中。此初始阶段完成后,live 代理会将持久数据复制到备份代理中,因为实时代理接收它。这意味着,如果 live 代理断开网络,备份代理会具有实时代理接收的所有持久数据。

由于复制通过网络同步数据,网络故障可能会导致网络隔离,使实时代理及其备份同时处于活动状态。

在复制 HA 策略中,实时和备份代理通过网络将其日志与彼此同步。
仅实时(限 HA)

当正常停止实时代理时,它会将消息和事务状态复制到另一个实时代理,然后关闭。然后,客户端可以重新连接到其他代理,以继续发送和接收消息。

在只读 HA 策略中,代理将其消息和事务状态复制到另一个代理。

其他资源

16.3.1.3. 复制策略限制

网络隔离(有时称为"脑裂")是复制高可用性(HA)策略的一个限制。您应该了解它的发生方式,以及如何避免它。

如果实时代理及其备份丢失了连接,则网络隔离可能会发生。在这种情况下,实时代理及其备份可以同时处于活动状态。具体来说,如果备份代理仍可以连接到集群中半数的活跃代理,它也会变为活跃状态。因为在这种情况下,代理之间没有消息复制,因此它们各自为客户端和处理信息提供信息,而不会互相了解。在这种情况下,每个代理都有完全不同的日志。从这一状况中恢复可能非常困难,在某些情况下是不可能的。

为了避免网络隔离,请考虑以下几点:

  • 消除 网络隔离的任何可能,请使用 共享存储 HA 策略。
  • 如果使用复制 HA 策略,您可以使用 至少三个实时 备份对减少(但不消除)遇到网络隔离的机会。

    至少使用三个实时备份对可确保在实时备份代理对出现复制中断时,可以在任何 仲裁投票 中实现大多数结果。

以下是使用复制 HA 策略时的一些其他注意事项:

  • 当实时代理失败且备份转换为 live 时,在新备份代理附加到实时或发生恢复到原始实时代理前,不会进行进一步复制。
  • 如果 live-backup 组中的备份代理失败,则 live 代理将继续提供信息。但是,在将另一个代理添加为备份或原始备份代理被重启前,消息才会被复制。在此期间,消息仅会被保留到 live 代理。
  • 假设 live-backup pair 中的两个代理都已关闭,但现在都可重启。在这种情况下,为了避免消息丢失,您需要首先重启最新活跃的代理。如果最新活跃的代理是 backup 代理,则需要手动将此代理重新配置为 master 代理,以便首先重启它。

16.3.2. 配置共享存储高可用性

您可以使用共享存储高可用性(HA)策略在代理集群中实施 HA。使用共享存储时,实时和备份代理都访问共享文件系统上的通用目录,通常是存储区域网络(SAN)或网络文件系统(NFS)服务器。如果您配置了基于 JDBC 的持久性,您也可以将代理数据存储在指定的数据库中。使用共享存储时,如果 live 代理失败,备份代理会从共享存储中加载消息数据,并接管失败的实时代理。

通常,SAN 提供更好的性能(例如,速度)与 NFS 服务器,如果可用,建议使用这个选项。如果您需要使用 NFS 服务器,请参阅 Red Hat AMQ 7 支持的配置 以了解有关 AMQ Broker 支持的网络文件系统的更多信息。

在大多数情况下,您应使用共享存储 HA 而不是复制。由于共享存储不会通过网络复制数据,它通常比复制性能更好。共享存储还避免了网络隔离(也称为"脑裂")问题,其中实时代理及其备份同时处于活动状态。

注意

使用共享存储时,备份代理的启动时间取决于消息日志的大小。当备份代理接管失败的实时代理时,它会从共享存储中加载日志。如果日志包含大量数据,该过程会花费时间。

16.3.2.1. 配置 NFS 共享存储

使用共享存储高可用性时,您必须将实时和备份代理配置为使用共享文件系统中的通用目录。通常,您使用存储区域网络(SAN)或网络文件系统(NFS)服务器。

在从每个代理机器实例上挂载 NFS 服务器导出目录时,以下列出了一些建议的配置选项。

同步
指定所有更改都会立即刷新到磁盘。
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 秒(60 秒),重新传输值为 5 次重试可能会导致 AMQ Broker 检测到 NFS 断开连接。

其他资源

16.3.2.2. 配置共享存储高可用性

此流程演示了如何为代理集群配置共享存储高可用性。

先决条件

  • 共享存储系统必须可以被 live 和 backup 代理访问。

    • 通常,您使用存储区域网络(SAN)或网络文件系统(NFS)服务器来提供共享存储。有关支持的网络文件系统的更多信息,请参阅 Red Hat AMQ 7 支持的配置
    • 如果您配置了基于 JDBC 的持久性,您可以使用指定的数据库来提供共享存储。要了解如何配置 JDBC 持久性,请参阅配置 JDBC Persistence

步骤

  1. 将集群中的代理分组到 live-backup 组中。

    在大多数情况下,live-backup 组应该由两个代理组成:live 代理和一个备份代理。如果您的集群中有 6 个代理,则需要三个 live-backup 组。

  2. 创建由一个实时代理和一个备份代理组成的第一个 live-backup 组。

    1. 打开 live broker 的 <broker-instance-dir>/etc/broker.xml 配置文件。
    2. 如果使用:

      1. 提供共享存储的网络文件系统,验证 live 代理的分页、绑定、日志和大型消息目录指向备份代理也可以访问的共享位置。

        <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 和 backup 代理可以连接到同一数据库,并在 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>BINDINGS_TABLE</bindings-table-name>
                  <message-table-name>MESSAGE_TABLE</message-table-name>
                  <large-message-table-name>LARGE_MESSAGES_TABLE</large-message-table-name>
                  <page-store-table-name>PAGE_STORE_TABLE</page-store-table-name>
                  <node-manager-store-table-name>NODE_MANAGER_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. 配置 live 代理,以将共享存储用于其 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>/etc/broker.xml 配置文件。
    5. 如果使用:

      1. 提供共享存储的网络文件系统,验证备份代理的分页、绑定、日志和大型消息目录指向与 live 代理相同的共享位置。

        <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-backup 对(一个与单一备份代理配合使用的实时代理)。如果 live 代理配置了多个备份,则不会发生故障恢复。相反,如果发生故障转移事件,备份代理将变为实时状态,下一个备份将成为备份。当原始实时代理重新上线时,它将无法启动失败,因为现在实时的代理已经有备份。

      restart-backup
      此属性控制在备份代理失败后是否自动重启备份代理。这个属性的默认值为 true
  3. 对集群中的每个剩余的 live-backup 组重复步骤 2。

16.3.3. 配置复制高可用性

您可以使用复制高可用性(HA)策略在代理集群中实施 HA。使用复制时,持久数据会在实时和备份代理之间同步。如果实时代理遇到失败,则会将消息数据同步到备份代理中,并接管失败的实时代理。

如果您没有共享文件系统,应使用 replication 作为共享存储的替代选择。但是,复制可能会导致网络隔离,实时代理及其备份同时存在。

复制要求 至少三个实时备份对 减少(但不消除)网络隔离风险。至少使用三个 live-backup 代理对可让集群使用 仲裁投票 以避免有两个实时代理。

以下部分解释了仲裁如何实现工作,以及如何为至少具有三个实时备份对的代理集群配置复制 HA。

注意

由于实时和备份代理必须通过网络同步其消息传递数据,因此复制会增加性能开销。此同步过程会阻止日志操作,但不会阻止客户端。您可以配置日志操作在数据同步时可以阻止的最大时间。

16.3.3.1. 关于仲裁投票

如果实时代理及其备份遇到中断的复制连接,您可以配置名为 仲裁投票 的过程,以减少网络隔离(或"脑裂")问题。在网络隔离期间,实时代理及其备份可以同时处于活动状态。

下表描述了 AMQ Broker 使用两种仲裁投票。

vote 类型描述initiator所需的配置参与者基于投票结果的操作

备份投票

如果备份代理丢失了与 live 代理的复制连接,备份代理会根据投票的结果决定是否开始。

备份代理

无。当备份代理丢失与复制合作伙伴的连接时,会自动进行备份投票。

但是,您可以通过为这些参数指定自定义值来控制备份投票的属性:

  • quorum-vote-wait
  • vote-retries
  • vote-retry-wait

集群中的其他实时代理

当备份代理从集群中的其他实时代理接收大多数(即 仲裁)投票时启动,表示其复制合作伙伴不再可用。

实时投票

如果实时代理丢失与复制合作伙伴的连接,实时代理决定根据此投票继续运行。

实时代理

当实时代理丢失与复制合作伙伴和 vote-on-replication-replication-replication-replication-failure 设置为 true 时,进行实时投票。已激活的备份代理被视为实时代理,并可启动实时投票。

集群中的其他实时代理

如果实时代理 没有从集群中 的其他实时代理收到大部分投票,这表示其集群连接仍处于活动状态。

重要

下面列出了一些重要事项,需要记录您的代理集群的配置如何影响仲裁投票的行为。

  • 要成功进行仲裁数,集群的大小必须允许实现大多数结果。因此,在使用复制 HA 策略时,集群应该 至少有三个 live-backup 代理对。
  • 您添加到集群中的更 live-backup 代理对越多,您增加了集群的整体容错能力。例如,假设您有三个实时备份对:如果丢失了完整的 live-backup 对,剩余的两个 live-backup 对便无法达到多数结果,则后续的仲裁投票。这种情形表示,集群中的任何进一步复制中断都可能导致实时代理关闭,并防止其备份代理启动。通过使用方法配置集群,例如五个代理对,集群可能会遇到至少两个故障,同时仍可确保任何仲裁投票中的大多数结果。
  • 如果您有意 减少 集群中 live-backup 代理对的数量,则之前为多数投票建立的阈值不会自动减少。在此期间,丢失的复制连接触发的任何仲裁投票都无法成功,从而使您的集群更容易受到网络隔离的影响。要使集群重新计算仲裁投票中的大多数阈值,请先关闭您从集群中移除的 live-backup 对。然后,重启集群中的剩余的 live-backup 对。当所有剩余的代理都已重启时,集群会重新计算仲裁票数阈值。

16.3.3.2. 为复制高可用性配置代理集群

以下流程描述了如何为 6broker 集群配置复制高可用性(HA)。在这个拓扑中,六个代理被分成三个实时备份对:三个实时代理各自与专用备份代理配对。

复制要求至少三个实时备份对减少(但不消除)网络隔离风险。

先决条件

  • 您必须有至少六个代理的代理集群。

    六个代理配置为三个实时备份对。有关在集群中添加代理的详情,请参考 第 16 章 设置代理集群

步骤

  1. 将集群中的代理分组到 live-backup 组中。

    在大多数情况下,live-backup 组应该由两个代理组成:live 代理和一个备份代理。如果您的集群中有 6 个代理,则需要三个 live-backup 组。

  2. 创建由一个实时代理和一个备份代理组成的第一个 live-backup 组。

    1. 打开 live broker 的 <broker-instance-dir>/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,则当 live 代理在以前的故障切换后重启时,它会搜索集群中具有相同节点 ID 的另一个代理。如果 live 代理找到具有相同节点 ID 的另一个代理,这代表在 live 代理失败时成功启动备份代理。在这种情况下,live 代理会将其数据与备份代理同步。然后,实时代理请求备份代理关闭。如果为故障恢复配置了备份代理,它会关闭。然后,实时代理恢复其活跃角色,客户端重新连接它。

      警告

      如果您没有在 live 代理上将 check-for-live-server 设置为 true,则在以前的故障切换后重启 live 代理时可能会遇到重复的消息处理。特别是,如果您重启将此属性设置为 false 的 live 代理,则 live 代理不会将数据与备份代理同步。在这种情况下,live 代理可能会处理与备份代理已经处理相同的信息,从而导致重复。

      group-name
      此 live-backup 组的名称。要形成 live-backup 组,必须使用相同的组名称配置 live-backup 代理。
      vote-on-replication-failure

      此属性控制实时代理在中断的复制连接时是否启动仲裁 投票,称为实时投票

      实机投票是一种实时代理方法,决定其或其合作伙伴是中断的复制连接的原因。根据投票的结果,实时代理保持运行或关闭。

      重要

      要成功进行仲裁数,集群的大小必须允许实现大多数结果。因此,在使用复制 HA 策略时,集群应该 至少有三个 live-backup 代理对。

      您在集群中配置的代理对越多,增加集群的整体容错性越大。例如,假设您有三个 live-backup 代理对。如果丢失与完整 live-backup 对的连接,剩余的两个 live-backup 对不再会获得多数结果是仲裁投票。这种情形意味着任何后续复制中断都可能导致实时代理关闭,并防止其备份代理启动。通过使用方法配置集群,例如五个代理对,集群可能会遇到至少两个故障,同时仍可确保任何仲裁投票中的大多数结果。

    3. 为 live 代理配置任何其他 HA 属性。

      这些额外的 HA 属性具有适用于大多数常见用例的默认值。因此,如果您不希望默认行为,您只需要配置这些属性。如需更多信息,请参阅 附录 F, 复制高可用性配置元素

    4. 打开备份代理的 <broker-instance-dir>/etc/broker.xml 配置文件。
    5. 配置备份(即从机)代理,将复制用于其 HA 策略。

      <configuration>
          <core>
              ...
              <ha-policy>
                  <replication>
                      <slave>
                          <allow-failback>true</allow-failback>
                          <restart-backup>true</restart-backup>
                          <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-backup 对(一个与单一备份代理配合使用的实时代理)。如果 live 代理配置了多个备份,则不会发生故障恢复。相反,如果发生故障转移事件,备份代理将变为实时状态,下一个备份将成为备份。当原始实时代理重新上线时,它将无法启动失败,因为现在实时的代理已经有备份。

      restart-backup
      此属性控制在备份代理失败后是否自动重启备份代理。这个属性的默认值为 true
      group-name
      此备份应连接的 live 代理的组名称。备份代理仅连接到共享相同组名称的实时代理。
      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 组都一次。

其他资源

16.3.4. 使用 live-only 配置有限的高可用性

只使用实时 HA 策略可让您在不丢失信息的情况下在集群中关闭代理。使用只读实时代理时,它会安全停止实时代理,将其消息和事务状态复制到另一个实时代理,然后关闭。然后,客户端可以重新连接到其他代理,以继续发送和接收消息。

仅限实时 HA 策略仅在代理安全停止时处理情形。它无法处理意外的代理失败。

虽然只读 HA 会阻止消息丢失,但可能无法保留消息顺序。如果配置了只读 HA 的代理已停止,其消息将附加到另一代理队列的结尾。

注意

当代理准备缩减时,它会在其客户端断开连接前向客户端发送消息,告知它们已准备好处理其消息。但是,只有在初始代理完成缩减后,客户端才会重新连接到新的代理。这样可确保当客户端重新连接时,任何状态(如队列或事务)都可以在其他代理上可用。客户端重新连接时,常规重新连接设置应用,因此应设置足够高以应对缩减所需的时间。

这个步骤描述了如何在集群中配置每个代理来缩减。完成此步骤后,每当代理被安全停止后,它将将其消息和事务状态复制到集群中的另一个代理中。

步骤

  1. 打开第一个代理的 <broker-instance-dir>/etc/broker.xml 配置文件。
  2. 将代理配置为使用只读 HA 策略。

    <configuration>
        <core>
            ...
            <ha-policy>
                <live-only>
                </live-only>
            </ha-policy>
            ...
        </core>
    </configuration>
  3. 配置用于缩减代理集群的方法。

    指定此代理应该缩减的代理或一组代理。

    将缩减为…​do this…​

    集群中的特定代理

    指定要缩减的代理连接器。

    <live-only>
        <scale-down>
            <connectors>
                <connector-ref>broker1-connector</connector-ref>
            </connectors>
        </scale-down>
    </live-only>

    集群中的所有代理

    指定 broker 集群的发现组。

    <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. 对集群中的每个剩余的代理重复此步骤。

其他资源

  • 有关使用 live-only 缩减集群的代理集群示例,请参阅 缩减示例程序

16.3.5. 使用共存备份配置高可用性

您可以将备份代理与另一个实时代理位于同一个 JVM 中,而不是配置 live-backup 组。在此配置中,每个 live 代理配置为请求另一个实时代理以在 JVM 中创建并启动备份代理。

图 16.4. 共存 live 和 backup 代理

HA Colocated

您可以将 colocation 与共享存储或复制用作高可用性(HA)策略。新的备份代理从创建它的 live 代理继承其配置。备份的名称被设置为 colocated_backup_n,其中 n 是创建 live 代理的备份数量。

另外,备份代理会继承其连接器的配置以及来自创建它的 live 代理的接收器。默认情况下,端口偏移 100 应用于每个端口。例如,如果 live 代理具有端口 61616 的接受者,则创建的第一个备份代理将使用端口 61716,第二个备份将使用 61816,以此类推。

日志、大型消息和分页的目录会根据您选择的 HA 策略进行设置。如果您选择共享存储,请求代理会通知要使用的目标代理。如果选择复制,则目录从创建代理继承,并将新备份的名称附加到其中。

此流程将集群中的每个代理配置为使用共享存储 HA,并请求创建备份并与集群中的另一个代理在一起。

步骤

  1. 打开第一个代理的 <broker-instance-dir>/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 (可选)
    从备份端口偏移中排除连接器。如果您已经为应当排除在备份端口偏移中排除的外部代理配置了任何连接器,请为每个连接器添加一个 <connector-ref>
    master
    此代理的共享存储或复制故障转移配置。
    slave
    此代理备份的共享存储或复制故障转移配置。
  3. 对集群中的每个剩余的代理重复此步骤。

其他资源

  • 有关使用在一起备份的代理集群示例,请参阅 HA 示例程序

16.3.6. 将客户端配置为故障切换

在代理集群中配置高可用性后,您要将客户端配置为故障切换。客户端故障转移可确保如果代理失败,连接到它的客户端可以在最短停机时间的情况下重新连接到集群中的另一个代理。

注意

如果出现临时网络问题,AMQ Broker 会自动重新连接到同一代理。这和故障转移类似,但客户端重新连接到同一代理。

您可以配置两种不同类型的客户端故障切换:

自动客户端故障切换
客户端在第一次连接时接收代理集群的相关信息。如果连接了代理失败,客户端会自动重新连接到代理的备份,并且备份代理会在故障切换前重新创建任何会话和使用者。
应用程序级客户端故障转移
作为自动客户端故障切换的替代选择,您可以在故障处理程序中使用您自己的自定义重新连接逻辑对客户端应用进行编码。

步骤

16.4. 启用消息重新发布

如果您的代理集群使用 on-demand 消息负载均衡,您可以配置 消息重新分发以防止消息在没有 消费者使用消息的队列中是"stuck"。

本节包含有关:

16.4.1. 了解消息重新分发

代理集群使用负载均衡来在集群中分发消息负载。在集群连接中配置负载均衡时,如果您将 message-load-balancing 设置为 ON_DEMAND,则代理仅将消息转发到具有匹配使用者的其他代理。此行为可确保消息不会移到没有消费者使用消息的队列。但是,如果在将消息转发到代理后与队列连接有一个接近的使用者,这些消息会成为队列中的"stuck",且未被使用。此问题有时称为 星号

消息重新分发通过自动将消息从没有消费者到具有匹配使用者的代理的队列自动重新分发,从而防止出现混乱的问题。

16.4.1.1. 使用消息过滤器重新分配消息的限制

消息 重新分发不支持 使用者使用过滤器(也称为 选择器)。带有过滤器的用户的常见用例是请求模式,使用关联 ID。例如,请考虑以下情境:

  1. 您有一个两个代理( brokerAbrokerB )集群。每个代理都配置,将 redistribution-delay 设置为 0,message-load-balancing 设置为 ON_DEMAND
  2. brokerA and brokerB each has a queue named myQueue.
  3. 根据请求,生产者发送发送到 brokerA 上队列 myQueue 的消息。该消息具有关联 ID 属性,名为 myCorrelID,值设为 10
  4. 消费者通过过滤器 myCorrelID=5 连接到 brokerA 上的 myQueue。此过滤器与消息的关联 ID 值不匹配。
  5. 另一个消费者通过过滤器 myCorrelID=10 连接到 brokerB 上的队列 myQueue。此过滤器与消息的关联 ID 值匹配。

    在这种情况下,虽然 brokerB 上的使用者过滤器与消息匹配,但该消息 不会从 brokerA 重新分发给 brokerB,因为 brokerA 上存在队列 myQueue 的使用者。

在前面的场景中,您可以通过在请求发送到生产者 之前创建 使用者来确保所需的客户端收到消息。该消息会立即路由到消费者,过滤器与消息的关联 ID 匹配。不需要重新分发。

其他资源

16.4.2. 配置消息重新分发

以下操作过程演示了如何配置消息重新分发。

步骤

  1. 打开 <broker-instance-dir>/etc/broker.xml 配置文件。
  2. <cluster-connection> 元素中,验证 <message-load-balancing> 是否已设置为 <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. <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. 对集群中的每个额外代理重复此步骤。

其他资源

16.5. 配置集群消息分组

消息分组可让客户端发送特定类型的消息组,以便由同一消费者按顺序处理。通过为集群中的每个代理添加将处理程序分组,您可以确保客户端可以将分组的消息发送到集群中的任何代理,并且仍具有相同消费者使用的正确消息。

有两种分组处理程序: 本地 处理程序和 远程处理程序。它们可让代理集群将特定组中的所有信息路由到适当的队列中,以便预期的消费者可以使用正确的顺序使用它们。

先决条件

  • 集群中每个代理上应该至少有一个消费者。

    当消息固定到队列中的消费者时,具有相同组 ID 的所有消息都将路由到该队列。如果移除了使用者,则队列将继续接收消息,即使没有使用者也是如此。

步骤

  1. 在集群中的一个代理上配置本地处理程序。

    如果您使用高可用性,则应该是一个 master 代理。

    1. 打开 broker 的 <broker-instance-dir>/etc/broker.xml 配置文件。
    2. <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. 如果使用高可用性,请将本地处理器配置复制到主代理的 slave 代理。

    将本地处理程序配置复制到从属代理可防止本地处理程序的单点故障。

  3. 在集群的每个剩余代理上,配置远程处理程序。

    1. 打开 broker 的 <broker-instance-dir>/etc/broker.xml 配置文件。
    2. <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 毫秒。将此值设置为本地处理程序的值至少为一半。

其他资源

16.6. 将客户端连接到代理集群

您可以使用 AMQ JMS 客户端连接到集群。通过使用 JMS,您可以将消息传递客户端配置为动态或静态发现代理列表。您还可以配置客户端负载均衡,以分发从集群范围内的连接创建的客户端会话。

步骤

第 17 章 配置多站点容错消息传递系统

大规模企业消息传递系统通常具有位于地理位置分散的数据中心的离散代理集群。如果数据中心中断,系统管理员可能需要保留现有的消息传递数据,并确保客户端应用能够继续生成和使用消息。您可以使用特定的代理拓扑和 Red Hat Ceph Storage 软件定义的存储平台来确保在数据中心停机期间的消息传递系统的连续性。这种类型的解决方案称为 多站点容错架构

以下小节介绍了如何保护消息传递系统不受数据中心中断的影响。这些部分提供有关:

注意

多站点容错不是数据中心内高可用性(HA)代理冗余的替代。基于 live-backup groups 的代理冗余功能可以针对单一集群中的单代理故障提供自动保护。相反,多站点容错可防止大规模数据中心中断。

注意

要使用 Red Hat Ceph Storage 来确保消息传递系统的连续性,您必须将代理配置为使用共享存储高可用性(HA)策略。您不能将代理配置为使用复制 HA 策略。有关这些策略的更多信息,请参阅实施高可用性。

17.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 集群池中复制数据的规则。

通过反映安装的基本物理组织,CRUSH 映射模型,从而解决关联设备故障的潜在来源,如物理代理、共享电源和共享网络。通过将此信息编码到集群映射中,CRUSH 可以在不同故障域(如数据中心)之间分隔对象副本,同时仍可在存储集群中维护数据的伪随机分发。这有助于防止数据丢失并启用集群处于降级状态。

Red Hat Ceph Storage 集群需要很多节点(物理或虚拟)才能运行。集群必须包括以下类型的节点:

监控节点

每个 monitor(MON)节点运行 monitor 守护进程(ceph-mon),该守护进程维护 cluster map 的主副本。集群映射包含集群拓扑。连接到 Ceph 集群的客户端从监控器检索 cluster map 的当前副本,这样客户端可以从集群读取和写入数据。

重要

Red Hat Ceph Storage 集群可以使用一个 monitor 节点运行;但是,为了确保生产集群的高可用性,红帽仅支持部署至少三个 monitor 节点的部署。至少三个 monitor 节点意味着,当一个监控器出现故障或不可用时,集群中剩余的 monitor 节点存在仲裁,以选择新的领导。

Manager 节点

每个管理器(MGR)节点运行 Ceph 管理器守护进程(ceph-mgr),它负责跟踪运行时指标和 Ceph 集群的当前状态,包括存储利用率、当前的性能指标和系统负载。通常,管理器节点与监控节点在一起(即位于同一主机机器上)。

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?

17.2. 安装 Red Hat Ceph Storage

AMQ Broker 多站点,容错架构使用红帽 Ceph 存储 3。通过跨数据中心复制数据,Red Hat Ceph Storage 集群有效地在单独的数据中心中创建一个共享存储供代理使用。您可以将代理配置为使用共享存储高可用性(HA)策略,并在 Red Hat Ceph Storage 集群中存储消息传递数据。

供生产环境使用的 Red Hat Ceph Storage 集群应该最少有:

  • 三个 monitor(MON)节点
  • 三个管理器(MGR)节点
  • 三个包含多个 OSD 守护进程的 Object Storage Device(OSD)节点
  • 三个元数据服务器(MDS)节点
重要

您可以在相同或独立的物理或虚拟机上运行 OSD、MON、MGR 和 MDS 节点。但是,为了确保 Red Hat Ceph Storage 集群中的容错,最好在不同的数据中心分发每种类型的节点。特别是,您必须确保在单个数据中心停机时,您的存储集群仍具有至少两个可用 MON 节点。因此,如果您在集群中有三个 MON 节点,这些节点必须在单独的数据中心的不同主机上运行。不要在单个数据中心中运行两个 MON 节点,因为此数据中心故障会使存储集群仅有一个剩余的 MON 节点。在这种情况下,存储集群将不再操作。

本节链接到的步骤演示了如何安装包含 MON、MGR、OSD 和 MDS 节点的 Red Hat Ceph Storage 3 集群。

先决条件

步骤

17.3. 配置 Red Hat Ceph Storage 集群

这个示例步骤演示了如何为容错配置 Red Hat Ceph 存储集群。您可以创建 CRUSH bucket,将对象存储设备(OSD)节点聚合到数据中心,反映您的实际负载、物理安装。另外,您还创建了一个规则,它告知 CRUSH 如何在您的存储池中复制数据。这些步骤会更新由 Ceph 安装创建的默认 CRUSH map。

先决条件

步骤

  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 bucket 是默认 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)和 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

下图显示了上一示例步骤所创建的红帽 Ceph 存储集群。存储群集有 OSD 整理到与数据中心对应的 CRUSH bucket 中。

代理灾难恢复 1

下图显示了第一个数据中心的可能布局,包括您的代理服务器。特别是,数据中心主机:

  • 两个 live-backup 代理对的服务器
  • 您在前面步骤中分配给第一个数据中心的 OSD 节点
  • 单个元数据服务器、监控和管理器节点。monitor 和 Manager 节点通常在同一机器上共存。
代理灾难恢复 2
重要

您可以在相同或独立的物理或虚拟机上运行 OSD、MON、MGR 和 MDS 节点。但是,为了确保 Red Hat Ceph Storage 集群中的容错,最好在不同的数据中心分发每种类型的节点。特别是,您必须确保在单个数据中心停机时,存储集群仍具有至少两个可用 MON 节点。因此,如果您在集群中有三个 MON 节点,这些节点必须在单独的数据中心的不同主机上运行。

下图显示了完整的拓扑示例。为确保存储集群中的容错能力,MON、MGR 和 MDS 节点分布到三个不同的数据中心。

代理灾难恢复 10
注意

在与代理服务器相同的数据中心中,为某些 OSD 节点定位主机机器并不意味着将消息传递数据存储在那些特定的 OSD 节点上。您可以将代理配置为将消息传递数据存储在 Ceph 文件系统中指定的目录中。然后,您的集群中的元数据服务器节点确定如何在您的数据中心的所有可用 OSD 中分发存储的数据,并在数据中心处理此数据的复制。后续部分显示如何配置代理,将消息传递数据存储在 Ceph 文件系统上。

下图说明了两个有代理服务器的数据中心之间的数据复制。

代理灾难恢复 3

其他资源

有关以下内容的更多信息:

  • 为您的红帽 Ceph 存储集群管理 CRUSH,请参见 CRUSH 管理
  • 您可以在存储池上设置的完整属性,请参阅池

17.4. 在代理服务器中挂载 Ceph 文件系统

在消息传递系统中配置代理以在 Red Hat Ceph Storage 集群中存储消息传递数据前,您首先需要挂载 Ceph 文件系统(CephFS)。

本节链接到的步骤演示了如何在代理服务器上挂载 CephFS。

先决条件

步骤

有关在代理服务器中挂载 Ceph 文件系统的说明,请参阅将 Ceph 文件系统作为内核客户端挂载

17.5. 在多站点容错消息传递系统中配置代理

要将代理配置为多站点、容错消息传递系统的一部分,您需要:

17.5.1. 添加备份代理

在每个数据中心中,您需要添加空闲的备份代理,这些代理可以从 live master-slave broker 组接管,在数据中心停止时关闭。您应该在空闲的备份代理中复制 live master 代理配置。您还需要配置备份代理,以便接受与现有代理相同的客户端连接。

在后续步骤中,您将了解如何将空闲备份代理配置为加入现有的 master-slave 代理组。您必须在单独的数据中心中找到空闲备份代理到 live master-slave 代理组。另外,建议您仅在数据中心失败时手动启动空闲备份代理。

下图显示了拓扑示例。

代理灾难恢复 4

其他资源

17.5.2. 将代理配置为 Ceph 客户端

添加需要容错系统的备份代理时,您必须为 Ceph 客户端角色配置所有代理服务器。客户端角色使代理可以在 Red Hat Ceph Storage 集群中存储数据。

要了解如何配置 Ceph 客户端,请参阅安装 Ceph 客户端角色

17.5.3. 配置共享存储高可用性

Red Hat Ceph Storage 集群有效地创建可用于不同数据中心的代理的共享存储。要确保消息在失败时为代理客户端仍可用,您需要配置 live-backup 组中的每个代理来使用:

  • 共享存储高可用性(HA)策略
  • Ceph 文件系统中的相同日志、分页和大型消息目录

以下步骤演示了如何在 live-backup 组的 master、从和闲置备份代理上配置共享存储 HA 策略。

步骤

  1. 编辑 live-backup 组中每个代理的 broker.xml 配置文件。将每个代理配置为使用 Ceph 文件系统中的相同分页、绑定、日志和大型消息目录。

    # Master Broker - DC1
    <paging-directory>mnt/cephfs/broker1/paging</paging-directory>
    <bindings-directory>/mnt/cephfs/data/broker1/bindings</bindings-directory>
    <journal-directory>/mnt/cephfs/data/broker1/journal</journal-directory>
    <large-messages-directory>mnt/cephfs/data/broker1/large-messages</large-messages-directory>
    
    # Slave Broker - DC1
    <paging-directory>mnt/cephfs/broker1/paging</paging-directory>
    <bindings-directory>/mnt/cephfs/data/broker1/bindings</bindings-directory>
    <journal-directory>/mnt/cephfs/data/broker1/journal</journal-directory>
    <large-messages-directory>mnt/cephfs/data/broker1/large-messages</large-messages-directory>
    
    # Backup Broker (Idle) - DC2
    <paging-directory>mnt/cephfs/broker1/paging</paging-directory>
    <bindings-directory>/mnt/cephfs/data/broker1/bindings</bindings-directory>
    <journal-directory>/mnt/cephfs/data/broker1/journal</journal-directory>
    <large-messages-directory>mnt/cephfs/data/broker1/large-messages</large-messages-directory>
  2. 将备份代理配置为其 HA 策略中的 master,如下所示。此配置设置可确保在手动启动时备份代理会立即成为 master。因为代理是一个闲置备份,所以您可以为活跃 master 代理指定的 failover-on-shutdown 参数不会应用。

    <configuration>
        <core>
            ...
            <ha-policy>
                <shared-store>
                    <master>
                    </master>
                </shared-store>
            </ha-policy>
            ...
        </core>
    </configuration>

其他资源

17.6. 在多站点容错消息传递系统中配置客户端

内部客户端应用程序是在与代理服务器位于同一数据中心的计算机上运行的机器上。下图显示了此拓扑。

代理灾难恢复 5

外部客户端应用程序是在代理数据中心外部的计算机上运行的机器上。下图显示了此拓扑。

代理灾难恢复 6

以下子部分描述了在数据中心中断时配置内部和外部客户端应用程序以连接到其他数据中心的备份代理的示例。

17.6.1. 配置内部客户端

如果您遇到数据中心中断,内部客户端应用程序将与您的代理一起关闭。要缓解这种情况,您必须有一个单独数据中心中可用的客户端应用程序实例。在数据中心停止时,您可以手动启动备份客户端以连接到已经手动启动的备份代理。

要启用备份客户端连接到备份代理,您需要与主数据中心中的客户端连接类似。

示例

以下是 AMQ Core Protocol JMS 客户端到主从代理组的基本连接配置。在本例中,host1host2 是 master 和 slave 代理的主机服务器。

<ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(“(tcp://host1:port,tcp://host2:port)?ha=true&retryInterval=100&retryIntervalMultiplier=1.0&reconnectAttempts=-1”);

要将备份客户端配置为在数据中心中断时连接到备份代理,请使用类似的连接配置,但只指定备份代理服务器的主机名。在本例中,备份代理服务器是 host3。

<ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(“(tcp://host3:port)?ha=true&retryInterval=100&retryIntervalMultiplier=1.0&reconnectAttempts=-1”);

其他资源

有关配置代理和客户端网络连接的更多信息,请参阅:

17.6.2. 配置外部客户端

要启用外部代理客户端在数据中心中断时继续生成或消耗消息传递数据,您必须将客户端配置为在另一个数据中心中切换到代理。如果是多站点容错的系统,您可以将客户端配置为故障转移到您在停机时手动启动的备份代理。

示例

下面是在主 master-slave 组不可用的情况下,将 AMQ Core Protocol JMS 和 AMQP JMS 客户端配置为故障转移到备份代理的示例。在这些示例中,host1host2 是主主 master 和 slave 代理的主机服务器,host3 是您在数据中心中断时手动启动的备份代理的主机服务器。

  • 要配置 AMQ Core Protocol JMS 客户端,请在客户端尝试连接的代理列表中包含备份代理。

    <ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(“(tcp://host1:port,tcp://host2:port,tcp://host3:port)?ha=true&retryInterval=100&retryIntervalMultiplier=1.0&reconnectAttempts=-1”);
  • 要配置 AMQP JMS 客户端,请在客户端上配置的故障转移 URI 中包含备份代理。

    failover:(amqp://host1:port,amqp://host2:port,amqp://host3:port)?jms.clientID=foo&failover.maxReconnectAttempts=20

其他资源

有关配置故障切换的更多信息:

17.7. 在数据中心中断期间验证存储集群健康状况

当您为容错配置 Red Hat Ceph Storage 集群时,集群将继续在不丢失数据的情况下处于降级状态,即使其中一个数据中心发生故障。

此流程演示了如何在处于降级状态时验证集群的状态。

步骤

  1. 要验证 Ceph 存储集群的状态,请使用 健康状态 命令:

    # ceph health
    # ceph status
  2. 要在命令行中查看集群的持续事件,请打开一个新终端。然后,输入:

    # ceph -w

当运行以上任何命令时,您会看到指示存储集群仍在运行的输出,但处于降级状态。特别是,您应该会看到一个类似如下的警告:

health: HEALTH_WARN
        2 osds down
        Degraded data redundancy: 42/84 objects degraded (50.0%), 16 pgs unclean, 16 pgs degraded

其他资源

  • 有关监控 Red Hat Ceph Storage 集群健康状况的更多信息,请参阅 监控

17.8. 在数据中心停止期间维持消息连续性

以下流程演示了如何在数据中心中断期间保持客户端可用的代理和关联的消息传递数据。特别是,当数据中心出现故障时,您需要:

  • 手动启动您创建的任何空闲备份代理,以便在失败的数据中心中的代理中接管。
  • 将内部或外部客户端连接到新的活跃代理。

先决条件

步骤

  1. 对于故障数据中心中的每个 master-slave 代理对,请手动启动您添加的空闲备份代理。

    代理灾难恢复 7
  2. 重新建立客户端连接。

    1. 如果您在失败的数据中心使用内部客户端,请手动启动您创建的备份客户端。如在 多站点、容错消息传递系统 中配置客户端 所述,您必须配置客户端连接到手动启动的备份代理。

      下图显示了新拓扑。

      代理灾难恢复 8
    2. 如果您有一个外部客户端,请根据其配置手动将外部客户端连接到新的活跃代理,或观察客户端是否自动切换到新的活跃代理。如需更多信息,请参阅配置外部客户端

      下图显示了新拓扑。

      代理灾难恢复 9

17.9. 重启之前失败的数据中心

当之前失败的数据中心恢复在线时,请按照以下步骤恢复消息传递系统的原始状态:

  • 重启托管 Red Hat Ceph Storage 集群节点的服务器
  • 在消息传递系统中重启代理
  • 重新建立从客户端应用程序到恢复的代理的连接

以下子部分显示执行这些步骤。

17.9.1. 重启存储集群服务器

当您重启之前故障的数据中心中的 monitor、元数据服务器、管理器和 Object Storage Device(OSD)节点时,您的 Red Hat Ceph Storage 集群可以自我修复来恢复完整的数据冗余。在此过程中,Red Hat Ceph Storage 根据需要自动将数据回填到恢复的 OSD 节点。

要验证您的存储集群是否自动修复和恢复完整的数据冗余,请在 数据中心中断期间使用之前在验证存储集群健康状况 中显示的命令。当您重新执行这些命令时,您会看到先前 HEALTH_WARN 消息所示的百分比降级开始改进,直到它返回 100%。

17.9.2. 重启代理服务器

以下流程演示了如何在存储集群不再处于降级状态时重启代理服务器。

步骤

  1. 停止连接到您在数据中心停机时手动启动的代理的任何客户端应用程序。
  2. 停止您手动启动的备份代理。

    1. 在 Linux 中:

      BROKER_INSTANCE_DIR/bin/artemis stop
    2. 在 Windows 上:

      BROKER_INSTANCE_DIR\bin\artemis-service.exe stop
  3. 在之前失败的数据中心,重启原始 master 和 slave 代理。

    1. 在 Linux 中:

      BROKER_INSTANCE_DIR/bin/artemis run
    2. 在 Windows 上:

      BROKER_INSTANCE_DIR\bin\artemis-service.exe start

原始 master 代理会在重启主代理时自动恢复该角色。

17.9.3. 重新建立客户端连接

重启代理服务器后,请将客户端应用程序重新连接到这些代理。以下小节描述了如何重新连接内部和外部客户端应用程序。

17.9.3.1. 重新连接内部客户端

内部客户端与恢复的代理是在同一个中运行的、以前失败的数据中心。要重新连接内部客户端,请重启它们。每个客户端应用程序都会重新连接到其连接配置中指定的恢复的 master 代理。

有关配置代理和客户端网络连接的更多信息,请参阅:

17.9.3.2. 重新连接外部客户端

外部客户端是在之前失败的数据中心外部运行的。根据客户端类型和 配置外部代理客户端 中的内容,您可以将客户端自动切换到备份代理,或者您手动建立此连接。当您恢复之前失败的数据中心时,您可以以类似方式从客户端重新建立到恢复的 master 代理的连接,如下所述。

  • 如果您将外部客户端配置为自动故障切换到备份代理,则在关闭备份代理时客户端会自动恢复到原始 master 代理,并重启原始 master 代理。
  • 如果您在数据中心停机时手动将外部客户端连接到备份代理,则必须手动将客户端重新连接到您重启的原始 master 代理。

第 18 章 日志

AMQ Broker 使用 JBoss Logging 框架进行日志记录,可通过 BROKER_INSTANCE_DIR/etc/logging.properties 配置文件进行配置。此配置文件是键值对列表。

您可以通过在 logging.properties 配置文件的 loggers 键中包含日志记录器,如下所示。

loggers=org.eclipse.jetty,org.jboss.logging,org.apache.activemq.artemis.core.server,org.apache.activemq.artemis.utils,org.apache.activemq.artemis.journal,org.apache.activemq.artemis.jms.server,org.apache.activemq.artemis.integration.bootstrap,org.apache.activemq.audit.base,org.apache.activemq.audit.message,org.apache.activemq.audit.resource

下表中显示了 AMQ Broker 中提供的日志记录器。

日志记录器描述

org.jboss.logging

根日志记录器。记录不由其他代理日志记录器处理的任何调用。

org.apache.activemq.artemis.core.server

记录代理内核

org.apache.activemq.artemis.utils

日志实用程序调用

org.apache.activemq.artemis.journal

日志日志调用

org.apache.activemq.artemis.jms

日志 JMS 调用

org.apache.activemq.artemis.integration.bootstrap

日志 bootstrap 调用

org.apache.activemq.audit.base

记录对所有 JMX 对象方法的访问

org.apache.activemq.audit.message

记录消息操作,如生产、消耗和浏览消息

org.apache.activemq.audit.resource

记录身份验证事件、从 JMX 或 AMQ Broker 管理控制台创建和删除代理资源,并在管理控制台中浏览消息

logger.handlers 键中也配置了两个默认的日志记录处理程序,如下方所示:

logger.handlers=FILE,CONSOLE
logger.handlers=FILE
日志记录器将日志条目输出到文件。
logger.handlers=CONSOLE
日志记录器将日志条目输出到 AMQ Broker 管理控制台。

18.1. 更改日志级别

所有日志记录器的默认日志记录级别为 INFO,在根日志记录器上配置,如下所示。

logger.level=INFO

您可以单独为所有其他日志记录器配置日志级别,如下所示。

logger.org.apache.activemq.artemis.core.server.level=INFO
logger.org.apache.activemq.artemis.journal.level=INFO
logger.org.apache.activemq.artemis.utils.level=INFO
logger.org.apache.activemq.artemis.jms.level=INFO
logger.org.apache.activemq.artemis.integration.bootstrap.level=INFO
logger.org.apache.activemq.audit.base.level=INFO
logger.org.apache.activemq.audit.message.level=INFO
logger.org.apache.activemq.audit.resource.level=INFO

下表描述了可用的日志记录级别。日志记录级别以升序列出,从最低程度上对最高顺序列出。

级别描述

FATAL

对于指示关键服务故障的事件,请使用 FATAL 日志级别。如果服务问题出现 FATAL 错误,则完全无法执行任何类型的请求。

ERROR

对指示请求中断的事件使用 ERROR 日志记录级别,或者可向请求提供服务。在存在此级别的错误时,服务应该 有一些 容量来继续服务请求。

WARN

对于可能指示非关键服务错误的事件,请使用 WARN 日志记录级别。请求预期可恢复的错误,或出现细微差别符合此描述。WARN 和 ERROR 之间的区别是供应用开发人员使用的。进行这种区分的简单条件是,错误是否需要用户寻求技术支持。如果错误需要技术支持,请将日志记录级别设置为 ERROR。否则,将级别设置为 WARN。

INFO

将 INFO 日志记录级别用于服务生命周期事件和其他重要相关的信息。给定服务类别的 INFO 级别消息应当清楚地指明该服务所处的状态。

DEBUG

将 DEBUG 日志记录级别用于记录生命周期事件信息的日志消息。对面向开发人员的信息或技术支持所需的深度信息使用此日志级别。启用 DEBUG 日志记录级别后,JBoss 服务器日志 不应 与服务器请求数量成比例增长。给定服务类别的 DEBUG 和 INFO 级别的消息应当清楚地指明该服务所处的状态,以及它所使用的代理资源;端口、接口、日志文件等。

TRACE

将 TRACE 日志级别用于直接与请求活动关联的日志消息。此类消息不应提交到日志记录器,除非日志记录器类别优先级阈值表示消息将被呈现。使用 Logger.isTraceEnabled() 方法来确定是否启用了类别优先级阈值。TRACE 级别日志记录可在需要时深入探测代理行为。启用 TRACE 日志级别后,JBoss 一次日志中的消息数量至少增加到 * N 其中 N 是代理收到的请求数量,另一个是 一些常量。服务器日志可能会增大到 N 的一些功率,具体取决于正在追踪的请求密集型层。

注意
  • INFOlogger.org.apache.activemq.audit.baselogger.org.apache.activemq.audit.message 的唯一可用日志记录级别,以及 logger.org.apache.activemq.audit.resource Audit loggers。
  • 为根日志记录器指定的日志记录级别决定了 所有 日志记录器的最详细的日志记录级别,即使其他日志记录器在其配置中指定更详细。例如,假设 org.apache.activemq.artemis.utils 具有 DEBUG 的指定日志记录,而根日志记录器 org.jboss.logging 指定了 WARN 的日志记录级别。在这种情况下,两个日志记录器都使用日志级别 WARN

18.2. 启用审计日志记录

有三种审计日志记录器可用于启用:基础审计日志记录器、消息审计日志记录器以及资源审计日志记录器。

基本审计记录(org.apache.activemq.audit.base)
记录对所有 JMX 对象方法 的访问,如创建和删除地址和队列。日志 指明这些操作是成功还是失败。
消息审计日志记录器(org.apache.activemq.audit.message)
记录与消息相关的代理操作,如生产、消耗或浏览消息。
资源审计日志记录器(org.apache.activemq.audit.resource)
记录来自客户端、路由和 AMQ Broker 管理控制台的身份验证成功或失败。另外,也记录从 JMX 或管理控制台创建、更新或删除队列,并在管理控制台中浏览消息。

您可以独立于其他审计日志记录器启用每个审计记录。默认情况下,每个审计日志记录器都被禁用(即日志记录级别设置为 ERROR,这是不是审计日志日志记录器的有效日志记录级别)。要启用其中一个审计日志记录,请将日志记录级别设置为 INFO。例如:

logger.org.apache.activemq.audit.base.level=INFO
重要

消息审计日志记录器在代理上的性能密集型路径上运行。启用日志记录器可能会对代理的性能造成负面影响,特别是代理在高消息传递负载下运行时。在需要高吞吐量的消息传递系统上,不建议使用消息审计记录。

18.3. 配置控制台日志记录

您可以使用以下键配置控制台日志记录。

handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler
handler.CONSOLE.properties=autoFlush
handler.CONSOLE.level=DEBUG
handler.CONSOLE.autoFlush=true
handler.CONSOLE.formatter=PATTERN
注意

handler.CONSOLE 引用了 logger.handlers 键中提供的名称。

下表描述了控制台日志配置选项。

属性描述

name

处理程序名称

encoding

处理程序使用的字符编码

level

日志记录级别,指定记录的消息级别。低于这个值的消息级别会被丢弃。

Formatter

定义格式器。请参阅 第 18.5 节 “配置日志记录格式”

autoflush

species 是否在每次写入后自动清除日志

目标

控制台处理程序的目标。该值可以是 SYSTEM_OUT 或 SYSTEM_ERR。

18.4. 配置文件日志记录

您可以使用以下密钥配置文件日志记录:

handler.FILE=org.jboss.logmanager.handlers.PeriodicRotatingFileHandler
handler.FILE.level=DEBUG
handler.FILE.properties=suffix,append,autoFlush,fileName
handler.FILE.suffix=.yyyy-MM-dd
handler.FILE.append=true
handler.FILE.autoFlush=true
handler.FILE.fileName=${artemis.instance}/log/artemis.log
handler.FILE.formatter=PATTERN
注意

handler.FILE 引用了 logger.handlers 键中提供的名称。

下表描述了文件日志配置选项。

属性描述

name

处理程序名称

encoding

处理程序使用的字符编码

level

日志记录级别,指定记录的消息级别。低于这个值的消息级别会被丢弃。

Formatter

定义格式器。请参阅 第 18.5 节 “配置日志记录格式”

autoflush

species 是否在每次写入后自动清除日志

append

指定是否在目标文件中附加

file

文件描述,由路径和可选相对路径组成。

18.5. 配置日志记录格式

formatter 描述了如何显示日志消息。以下是默认配置。

formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter
formatter.PATTERN.properties=pattern
formatter.PATTERN.pattern=%d{HH:mm:ss,SSS} %-5p [%c] %s%E%n

在前面的配置中,%s 是消息,%E 为异常(如果存在)。

格式与 Log4J 格式相同。有关完整描述,请点击此处

18.6. 客户端或嵌入式服务器日志

如果要启用客户端登录,则需要在客户端的类路径中包含 JBoss 日志记录 JAR。如果使用 Maven,请添加以下依赖项:

<dependency>
   <groupId>org.jboss.logmanager</groupId>
   <artifactId>jboss-logmanager</artifactId>
   <version>1.5.3.Final</version>
</dependency>
<dependency>
   <groupId>org.apache.activemq</groupId>
   <artifactId>artemis-core-client</artifactId>
   <version>1.0.0.Final</version>
</dependency>

启动 Java 程序时需要设置两个属性:第一种方法是将 Log Manager 设置为使用 JBoss Log Manager。这可以通过设置 '-Djava.util.logging.manager'property 来实现。例如:

-Djava.util.logging.manager=org.jboss.logmanager.LogManager

第二种方法是设置要使用的 logging.properties 文件的位置。这可以通过使用有效 URL 设置 -Dlogging.configuration 属性来实现。例如:

-Dlogging.configuration=file:///home/user/projects/myProject/logging.properties

以下是客户端的典型 logging.properties 文件:

# Root logger option
loggers=org.jboss.logging,org.apache.activemq.artemis.core.server,org.apache.activemq.artemis.utils,org.apache.activemq.artemis.journal,org.apache.activemq.artemis.jms,org.apache.activemq.artemis.ra

# Root logger level
logger.level=INFO
# ActiveMQ Artemis logger levels
logger.org.apache.activemq.artemis.core.server.level=INFO
logger.org.apache.activemq.artemis.utils.level=INFO
logger.org.apache.activemq.artemis.jms.level=DEBUG

# Root logger handlers
logger.handlers=FILE,CONSOLE

# Console handler configuration
handler.CONSOLE=org.jboss.logmanager.handlers.ConsoleHandler
handler.CONSOLE.properties=autoFlush
handler.CONSOLE.level=FINE
handler.CONSOLE.autoFlush=true
handler.CONSOLE.formatter=PATTERN

# File handler configuration
handler.FILE=org.jboss.logmanager.handlers.FileHandler
handler.FILE.level=FINE
handler.FILE.properties=autoFlush,fileName
handler.FILE.autoFlush=true
handler.FILE.fileName=activemq.log
handler.FILE.formatter=PATTERN

# Formatter pattern configuration
formatter.PATTERN=org.jboss.logmanager.formatters.PatternFormatter
formatter.PATTERN.properties=pattern
formatter.PATTERN.pattern=%d{HH:mm:ss,SSS} %-5p [%c] %s%E%n

18.7. AMQ Broker 插件支持

AMQ 支持自定义插件。您可以使用插件记录有关许多不同类型的事件的信息,这些事件通过 debug 日志只可用。可以一起注册、关联和执行多个插件。将根据注册的顺序执行插件,即首先执行注册的第一个插件。

您可以创建自定义插件并使用 ActiveMQServerPlugin 接口实施它们。这个接口可确保插件位于类路径上,并使用代理进行注册。由于所有接口方法都默认实施,因此您必须仅添加需要实施的必要行为。

18.7.1. 在类路径中添加插件

通过将相关的 .jar 文件添加到 BROKER_INSTANCE_DIR/lib 目录中,将自定义创建的代理插件添加到代理运行时。

如果您使用嵌入式系统,则将 .jar 文件放在内嵌应用程序的常规类路径下。

18.7.2. 注册插件

您必须在 broker.xml 配置文件中添加 broker-plugins 元素来注册插件。您可以使用 属性 子元素指定插件配置值。这些属性将在插件实例化后读取并传递到插件的初始(Map<String, String>)操作。

<broker-plugins>
   <broker-plugin class-name="some.plugin.UserPlugin">
      <property key="property1" value="val_1" />
      <property key="property2" value="val_2" />
   </broker-plugin>
 </broker-plugins>

18.7.3. 以编程方式注册插件

要以编程方式注册插件,请使用 registerBrokerPlugin() 方法,并传递您插件的新实例。以下示例显示了 UserPlugin 插件的注册:

Configuration config = new ConfigurationImpl();

config.registerBrokerPlugin(new UserPlugin());

18.7.4. 记录特定事件

默认情况下,AMQ 代理提供 LoggingActiveMQServerPlugin 插件来记录特定的代理事件。LoggingActiveMQServerplugin 插件默认是注释的,且不会记录任何信息。

下表描述了各个插件属性。将配置属性值设置为 true 以记录事件。

属性

描述

LOG_CONNECTION_EVENTS

创建或销毁连接时记录信息。

LOG_SESSION_EVENTS

创建或关闭会话时,记录信息。

LOG_CONSUMER_EVENTS

创建或关闭使用者时,记录信息。

LOG_DELIVERING_EVENTS

当消息发送到消费者时,以及消费者确认消息时,记录信息。

LOG_SENDING_EVENTS

当消息发送到地址并在代理中路由消息时,记录信息。

LOG_INTERNAL_EVENTS

当队列创建或销毁时、消息过期、桥接部署以及发生关键故障时记录信息。

LOG_ALL_EVENTS

记录以上所有事件的信息。

要将 LoggingActiveMQServerPlugin 插件配置为记录连接事件,请取消注释 broker.xml 配置文件中的 <broker-plugins> 部分。在注释的默认示例中,所有事件的值都设为 true

<configuration ...>
...
<!-- Uncomment the following if you want to use the Standard LoggingActiveMQServerPlugin plugin to log in events -->
           <broker-plugins>
         <broker-plugin class-name="org.apache.activemq.artemis.core.server.plugin.impl.LoggingActiveMQServerPlugin">
            <property key="LOG_ALL_EVENTS" value="true"/>
            <property key="LOG_CONNECTION_EVENTS" value="true"/>
            <property key="LOG_SESSION_EVENTS" value="true"/>
            <property key="LOG_CONSUMER_EVENTS" value="true"/>
            <property key="LOG_DELIVERING_EVENTS" value="true"/>
            <property key="LOG_SENDING_EVENTS" value="true"/>
            <property key="LOG_INTERNAL_EVENTS" value="true"/>
         </broker-plugin>
      </broker-plugins>
...
</configuration>

当您更改 <broker-plugins> 部分中的配置参数时,您必须重启代理以重新载入配置更新。这些配置更改不会根据 configuration-file-refresh-period 设置重新加载。

当日志级别设置为 INFO 时,事件发生后会记录一个条目。如果日志级别设置为 DEBUG,则会在事件之前和之后为生成日志条目,例如: CreateConsumer()afterCreateConsumer()。如果日志级别设为 DEBUG,则日志记录器会记录通知的更多信息(如果可用)。

附录 A. acceptor 和 Connector 配置参数

下表详细介绍了用于配置 Netty 网络连接的一些可用参数。参数及其值附加到连接字符串的 URI 中。请参阅 Network Connections:接收器和连接器 了解更多信息。每个表格以姓名形式列出参数,并记录它们是否与接收器或连接器一起使用。您可以使用一些参数,例如:只接受接受者。

注意

所有 Netty 参数都在类 org.apache.activemq.core.remoting.impl.netty.TransportConstants 中定义。可以在客户门户网站 上下载源代码。http://access.redhat.com/downloads

表 A.1. Netty TCP 参数

参数使用 with…​描述

batchDelay

两者

在将数据包写入接收器或连接器之前,可将代理配置为批量写入最多 批处理时间 毫秒。这可以提高非常小的消息的总吞吐量。它这样做的开支是消息传输的平均延迟增加。默认值为 0 ms。

connectionsAllowed

接收器

限制接受者允许的连接数量。达到此限制时,会向日志发出 DEBUG 级别的消息,并且连接被拒绝。使用中的客户端类型决定了连接被拒绝时会发生什么。

directDeliver

两者

当消息到达服务器并默认传送到等待消费者时,发送会在到达消息的同一个线程中进行。这在具有相对小的消息和少量使用者的环境中提供了很好的延迟,但总体吞吐量和可扩展性成本(尤其是在多核机器上)。如果您希望最小延迟并可能降低吞吐量,那么您可以使用 directDeliver 的默认值(即 true )。如果您要对延迟造成一些小的点击,但希望将 directDeliver 设置为 false

handshake-timeout

接收器

防止未经授权的客户端打开大量连接,并将它们保持打开。因为每个连接都需要一个文件句柄,所以它会消耗资源,然后不能用于其他客户端。

这个超时限制了连接可以消耗资源的时间,而无需通过身份验证。连接通过身份验证后,您可以使用资源限值设置来限制资源消耗。

默认值为 10 秒。您可以将其设置为任何其他整数值。您可以通过将选项设置为 0 或负数来关闭这个选项。

编辑超时值后,您必须重启代理。

localAddress

连接器

指定在连接到远程地址时客户端将使用的本地地址。这通常用于应用服务器,或者在运行嵌入式嵌入式时使用该地址来控制用于出站连接的地址。如果没有设置 local-address,则连接器将使用任何可用的本地地址。

localPort

连接器

指定在连接到远程地址时客户端将使用哪些本地端口。这通常在应用服务器中使用,或在运行嵌入式嵌入式时用来控制用于出站连接的端口。如果使用默认值,即 0,则连接器将让系统获取临时端口。有效端口为 0 到 65535

nioRemotingThreads

两者

当配置为使用 NIO 时,代理默认使用线程数等于三倍的内核数(或超线程),由 Runtime.getRuntime().availableProcessors() 来处理传入的数据包。如果要覆盖这个值,您可以通过指定此参数来设置线程数量。此参数的默认值为 -1,这意味着使用从 Runtime.getRuntime().availableProcessors().availableProcessors()的值。

tcpNoDelay

两者

如果这是 true,那么将禁用 Nagle 的算法。这是 Java(客户端)套接字选项。默认值为 true

tcpReceiveBufferSize

两者

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

tcpSendBufferSize

两者

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

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

摘要中,TCP 发送/接收方缓冲区大小应根据以下计算:

buffer_size = bandwidth * RTT.

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

对于 fast 网络,您可能想要从默认值增大缓冲区大小。

表 A.2. Netty HTTP 参数

参数使用 with…​描述

httpClientIdleTime

接收器

在发送空 HTTP 请求以便保持连接处于活动状态前,客户端可以闲置多长时间。

httpClientIdleScanPeriod

接收器

扫描空闲客户端的频率(以毫秒为单位)。

httpEnabled

接收器

不再需要。现在,代理支持单一端口将自动检测是否使用 HTTP 并配置其自身。

httpRequiresSessionId

两者

如果为 true,客户端将在第一个调用后等待接收会话 ID。当 HTTP 连接器连接到 servlet acceptor 时使用。不建议进行此配置。

httpResponseTime

接收器

在发送空的 HTTP 响应前,服务器可以等待的时间,以保持连接处于活动状态。

httpServerScanPeriod

接收器

扫描需要响应的客户端的频率,以毫秒为单位。

表 A.3. Netty TLS/SSL 参数

参数使用 with…​描述

enabledCipherSuites

两者

用于 SSL 通信的密码套件的逗号分隔列表。默认值为空,表示将使用 JVM 的默认值。

enabledProtocols

两者

用于 SSL 通信的协议的逗号分隔列表。默认值为空,表示将使用 JVM 的默认值。

forceSSLParameters

连接器

控制是否将该连接器设置为参数的任何 SSL 设置,而不是 JVM 系统属性(包括 javax.net.ssl 和 AMQ Broker 系统属性)来配置此连接器的 SSL 上下文。

有效值为 true 或者 false。默认值为:false

keyStorePassword

两者

在接受者上时,这是服务器端密钥存储的密码。

在连接器上使用时,这是客户端一侧密钥存储的密码。只有在您使用双向 SSL(即相互身份验证)时,这才与连接器相关。虽然可以在服务器上配置此值,但它由客户端下载和使用。如果客户端需要使用与服务器上设置的不同密码,那么它可以通过使用 customary javax.net.ssl.keyStorePassword 系统属性或 ActiveMQ 特定的 org.apache.ssl.keyStorePassword 系统属性来覆盖服务器端设置。如果客户端上的另一组件已经使用标准的 Java 系统属性,则特定于 ActiveMQ 的系统属性很有用。

keyStorePath

两者

如果用于接受者,这是持有服务器证书(无论是由颁发机构自签名还是签名)的服务器上的 SSL 密钥存储的路径。

在连接器中使用时,这是保存客户端证书的客户端 SSL 密钥存储的路径。只有在您使用双向 SSL(即相互身份验证)时,这才与连接器相关。虽然在服务器上配置了这个值,但客户端已下载并使用它。如果客户端需要使用不同于服务器上设置的路径,那么它可以通过使用 customary javax.net.ssl.keyStore 系统属性或 ActiveMQ 特定的 org.apache.ssl.keyStore 系统属性来覆盖服务器端设置。如果客户端上的另一组件已经使用标准的 Java 系统属性,则特定于 ActiveMQ 的系统属性很有用。

needClientAuth

接收器

告知客户端连接到此接受者,需要双向 SSL。有效值为 true 或者 false。默认值为:false

sslEnabled

两者

必须为 true 启用 SSL。默认值为:false

trustManagerFactoryPlugin

两者

定义实施 org.apache.activemq.api.core.TrustManagerFactoryPlugin 的类名称。

这是一个单一方法的简单接口,它返回 javax.net.ssl.TrustManagerFactory。当底层 javax.net.ssl.SSLContext 被初始化时,将使用 TrustManagerFactory。这允许对代理和客户端信任的人员或客户端信任进行精细自定义。

trustManagerFactoryPlugin 的值优先于应用到信任管理器的所有其他 SSL 参数(即 trustAlltruststoreProvidertruststorePathtruststorePasswordcrlPath)。

您需要将任何指定的插件放在代理的 Java 类路径上。您可以使用 BROKER_INSTANCE_DIR/lib 目录,因为它是类路径的一部分。

trustStorePassword

两者

当用于接受时,这是服务器端信任存储的密码。只有在您使用双向 SSL(即相互验证)时,这才与接受者相关。

在连接器中使用时,这是客户端信任存储的密码。虽然可以在服务器上配置此值,但它由客户端下载和使用。如果客户端需要使用与服务器上设置的不同密码,那么它可以通过使用 customary javax.net.ssl.trustStorePassword 系统属性或 ActiveMQ 特定的 org.apache.ssl.trustStorePassword 系统属性来覆盖服务器端设置。如果客户端上的另一组件已经使用标准的 Java 系统属性,则特定于 ActiveMQ 的系统属性很有用。

sniHost

两者

在接受者中使用时,sni Host 是一个正则表达式,用于匹配传入 SSL 连接中的 server_name 扩展(有关此扩展的更多信息,请参阅 https://tools.ietf.org/html/rfc6066)。如果名称不匹配,则拒绝与接受者的连接。如果出现这种情况,则会记录 WARN 信息。

如果传入连接不包含 server_name 扩展,则接受连接。

在连接器中使用时,sniHost 值用于 SSL 连接上的 server_name 扩展。

sslProvider

两者

用于更改 JDKOPENSSL 之间的 SSL 提供程序。默认为 JDK

如果设置为 OPENSSL,可以在您的类路径中添加 netty-tcnative 以使用原生安装的 OpenSSL。

如果要使用通过 OpenSSL 支持的特殊密码suite-elliptic curve 组合,但没有通过 JDK 供应商支持,这个选项会很有用。

trustStorePath

两者

对于接受者,这是包含服务器信任的所有客户端的密钥的 SSL 密钥存储的路径。只有在您使用双向 SSL(即相互验证)时,这才与接受者相关。

在连接器上使用时,这是客户端 SSL 密钥存储的路径,该存储包含客户端信任的所有服务器的公钥。虽然可以在服务器上配置此值,但它由客户端下载和使用。如果客户端需要使用与服务器上设置的不同路径,那么它可以通过使用 customary javax.net.ssl.trustStore 系统属性或 ActiveMQ 特定的 org.apache.ssl.trustStore 系统属性来覆盖服务器端设置。如果客户端上的另一组件已经使用标准的 Java 系统属性,则特定于 ActiveMQ 的系统属性很有用。

useDefaultSslContext

连接器

允许连接器使用"默认" SSL 上下文(通过 SSLContext.getDefault()),该上下文可通过客户端(通过 SSLContext.setDefault(SSLContext))以编程方式设置。

如果此参数设为 true,则忽略除 sslEnabled 外所有其他与 SSL 相关的参数。有效值为 true 或者 false。默认值为:false

verifyHost

两者

当用于接收器时,连接客户端的 SSL 证书的 CN 将与其主机名进行比较,以验证它们是否匹配。这仅适用于双向 SSL。

在连接器中使用时,服务器的 SSL 证书的 CN 与其主机名进行比较,以验证它们是否匹配。这对单向和双向 SSL 来说都很有用。

有效值为 true 或者 false。默认值为:false

wantClientAuth

接收器

告知客户端连接到此接受者,会请求双向 SSL,但非强制要求。有效值为 true 或者 false。默认值为:false

如果属性 needClientAuth 设为 true,则该属性将具有优先权,并且忽略 wishClientAuth

附录 B. 地址设置配置元素

下表列出了 address-setting 的所有配置元素。请注意,一些元素被标记为 DEPRECATED。使用建议的替换来避免潜在的问题。

表 B.1. 地址设置元素

Name描述

address-full-policy

确定在配置了 max-size-bytes 的地址变为满时会发生什么。可用的策略有:

PAGE :发送到完整地址的消息将传给磁盘。

DROP :发送到完整地址的消息将被静默丢弃。

FAIL :发送到完整地址的消息将被丢弃,消息制作者将收到异常。

BLOCK :消息制作者将在尝试并发送任何进一步的消息时阻止。

注意

BLOCK 策略仅适用于 AMQP、OpenWire 和 Core Protocol 协议,因为它们功能流控制。

auto-create-addresses

当客户端发送消息到 或 试图使用映射到队列的地址的队列中时,是否会自动创建地址。默认值为 true

auto-create-dead-letter-resources

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

如果参数设置为 true,代理会自动创建一个 <address> 元素来定义死信地址和关联的死信队列。自动创建的 <address> 元素的名称与您为 <dead-letter-address> 指定的 name 值匹配。

auto-create-jms-queues

已弃用:使用 auto-create-queues 替代。决定当 JMS 制作者或消费者尝试使用此类队列时,此代理是否应该自动创建与地址设置对应的 JMS 队列。默认值为:false

auto-create-jms-topics

已弃用:使用 auto-create-queues 替代。决定,当 JMS 制作者或消费者尝试使用此类队列时,此代理是否应该自动创建与地址设置匹配的 JMS 主题。默认值为:false

auto-create-queues

当客户端向队列发送消息或试图使用队列中的消息时,是否会自动创建队列。默认值为 true

auto-delete-addresses

当代理不再有任何队列时,是否删除自动创建的地址。默认值为 true

auto-delete-jms-queues

已弃用:改为使用 auto-delete-queues。确定当 AMQ Broker 没有使用者且没有消息时,是否应自动删除自动创建的 JMS 队列。默认值为:false

auto-delete-jms-topics

已弃用:改为使用 auto-delete-queues。确定当 AMQ Broker 没有使用者且没有消息时,是否应自动删除自动创建的 JMS 主题。默认值为:false

auto-delete-queues

是否在队列没有使用者且没有消息时删除自动创建的队列。默认值为 true

config-delete-addresses

当重新加载配置文件时,此设置指定如何处理从配置文件中删除的地址(及其队列)。您可以指定以下值:

OFF (默认)
重新加载配置文件时,不会删除该地址。
FORCE
重新加载配置文件时,将删除地址及其队列。如果队列中有任何消息,它们也会被删除。

config-delete-queues

当重新加载配置文件时,此设置指定如何处理已从配置文件中删除的队列。您可以指定以下值:

OFF (默认)
重新加载配置文件时,队列不会被删除。
FORCE
重新加载配置文件时,队列将被删除。如果队列中有任何消息,它们也会被删除。

dead-letter-address

代理向发送死信息的地址。

dead-letter-queue-prefix

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

dead-letter-queue-suffix

代理应用到自动创建的死信队列的后缀。未定义默认值(即代理不应用后缀)。

default-address-routing-type

自动创建的地址中使用的路由类型。默认值为 MULTICAST

default-max-consumers

这个队列上允许的消费者的最大数量。默认值为 200

default-purge-on-no-consumers

在没有消费者后,是否清除队列的内容。默认值为:false

default-queue-routing-type

自动创建队列中使用的路由类型。默认值为 MULTICAST

enable-metrics

指定配置的 metrics 插件(如 Prometheus 插件)是否为匹配的地址 或一组 地址收集指标。默认值为 true

expiry-address

将接收过期信息的地址。

expiry-delay

定义将使用默认到期时间(以毫秒为单位)消息的过期时间。默认值为 -1,这代表没有过期时间。

last-value-queue

队列是否只使用最后的值。默认值为:false

management-browse-page-size

管理资源可以浏览的有多少条消息。默认值为 200

max-delivery-attempts

在发送到死信地址前尝试发送消息的次数。默认值为 10

max-redelivery-delay

重新delivery-delay 的最大值,以毫秒为单位。

max-size-bytes

这个地址的最大内存大小,以字节为单位。当 address-full-policyPAGINGBLOCKFAIL 时,这个值以字节表示法来指定,如 "K"、"Mb" 和 "GB"。默认值为 -1,它表示以字节为单位。这个参数用于通过限制特定地址空间消耗的内存量来保护代理内存。此设置不表示客户端目前存储在代理地址空间中所发送的字节数。它是代理内存使用率的估计。此值根据运行时条件和某些工作负载而有所不同。建议您分配可为每个地址空间提供的最大内存量。在典型的工作负载下,代理大约需要 150% 到内存中未完成消息的有效负载大小 200%。

max-size-bytes-reject-threshold

address-full-policyBLOCK 时使用。代理开始拒绝消息前可以到达的最大大小(以字节为单位)。配合使用用于 AMQP 协议的 max-size-bytes。默认值为 -1,这表示没有限制。

message-counter-history-day-limit

为此地址保留消息计数器历史记录的天数。默认值为 0

page-max-cache-size

在页导航期间保留在内存中的页面文件数,以优化 I/O。默认值为 5

page-size-bytes

分页大小(以字节为单位)。也支持字节表示法,如 KMbGB。默认值为 10485760 字节,几乎是 10.5 MB。

redelivery-delay

在红色发音消息前等待的时间(以毫秒为单位)。默认值为 0

redelivery-delay-multiplier

应用到 redelivery-delay 参数的倍数。默认值为 1.0

redistribution-delay

定义在重新分发任何消息之前,在队列中以毫秒为单位等待的等待时间。默认值为 -1

send-to-dla-on-no-route

当设置为 true 时,如果无法路由到任何队列,则会将消息发送到配置的死信地址。默认值为:false

slow-consumer-check-period

对缓慢消费者进行检查的频率(以秒为单位)。默认值为 5

slow-consumer-policy

决定当确定缓慢的消费者时会发生什么。有效选项为 KILLNOTIFYKILL 会终止消费者的连接,这会影响使用同一连接的任何客户端线程。NOTIFY 发送 CONSUMER_SLOW 管理通知给客户端。默认值为 NOTIFY

slow-consumer-threshold

在消费者被视为速度较慢之前,允许最小消息消耗率。按消息/秒来衡量。默认值为 -1,它未绑定。

附录 C. Cluster Connection Configuration 元素

下表列出了 cluster-connection 的所有配置元素。

表 C.1. Cluster Connection Configuration 元素

Name描述

address

每个集群连接只适用于与 address 字段中指定的值匹配的地址。如果未指定地址,则所有地址都将负载均衡。

address 字段还支持以逗号分隔的地址列表。使用 exclude 语法 ! 阻止地址匹配。以下是几个地址示例:

jms.eu
匹配以 jms.eu 开头的所有地址。
!JMS.eu
匹配除以 jms.eu开头的所有地址
jms.eu.uk,jms.eu.de
匹配以 jms.eu.ukjms.eu.de开头的所有地址
jms.eu,!jms.eu.uk
匹配以 jms.eu 开头的所有地址,但不匹配从 jms.eu.uk开头的所有地址
注意

您不应该具有多个与重叠地址的集群连接(例如,"europe"和"europe.news"),因为相同的消息可以在多个集群连接之间分布,这可能导致重复的交付。

call-failover-timeout

在故障转移尝试期间进行调用时,请使用。默认值为 -1,或者没有超时。

call-timeout

当数据包通过集群连接发送时,并且是一个阻塞调用,call-timeout 决定在引发异常前的回复将等待的时间(以毫秒为单位)。默认值为 30000

check-period

检查集群连接是否无法从另一个代理接收 ping 的时间间隔(毫秒)。默认值为 30000

confirmation-window-size

用于发送从连接的代理确认的窗口的大小(以字节为单位)。当代理收到 confirmation-window-size 字节时,它会通知其客户端。默认值为 1048576。值 -1 表示没有窗口。

connector-ref

标识 传输到集群中其他代理的连接器,以便它们具有正确的集群拓扑。此参数是必需的。

connection-ttl

如果停止从集群中的特定代理接收信息,则集群连接应该保持多长时间。默认值为 60000

discovery-group-ref

指向用于与集群中的其他代理通信的 发现 组。此元素必须包含属性 discovery-group-name,它必须与之前配置的 discovery-groupname 属性匹配。

initial-connect-attempts

设置系统最初在集群中尝试连接代理的次数。如果实现 max-retry,则此代理将会被永久关闭,系统不会将信息路由到此代理。默认为 -1,这意味着重试有限。

max-hops

将代理配置为对消息进行负载平衡,以限制为仅在链中作为中间人连接到该代理的代理。这可实现更复杂的拓扑,同时仍提供消息负载平衡。默认值为 1,这意味着信息仅分发到直接连接到此代理的其他代理。这个参数是可选的。

max-retry-interval

重试的最大延迟时间,以毫秒为单位。默认值为 2000

message-load-balancing

确定信息是否在集群中的其他代理之间分布。包含 message-load-balancing 元素以启用负载平衡。默认值为 ON_DEMAND。您还可以提供一个值。有效值为:

OFF
禁用负载平衡。
STRICT
将消息转发到具有匹配队列的所有代理,无论队列是否有活跃消费者还是匹配的选择器。
ON_DEMAND
确保消息仅转发到具有活跃消费者或匹配的选择器的代理。

min-large-message-size

如果消息大小(以字节为单位)大于 min-large-message-size,它将在通过网络发送到其他群集成员时分割成多个片段。默认值为 102400

notification-attempts

在连接到集群时,集群连接应广播自己的次数。默认值为 2

notification-interval

在附加到集群时,集群连接应如何广播自己。默认值为 1000

producer-window-size

用于对集群连接进行制作流控制的大小(以字节为单位)。默认情况下,它已被禁用,但如果在集群中使用真正大的消息,您可能需要设置值。值 -1 表示没有窗口。

reconnect-attempts

设置系统尝试重新连接到集群中的代理的次数。如果实现 max-retry,则此代理将永久关闭,并且系统将停止将消息路由到此代理。默认为 -1,这意味着重试有限。

retry-interval

确定重试尝试间隔(以毫秒为单位)。如果创建集群连接,且目标代理没有启动或启动,则来自其他代理的集群连接将重试连接到目标,直到它恢复为止。这个参数是可选的。默认值为 500 毫秒。

retry-interval-multiplier

每次重新尝试后增加 retry-interval 的倍数。默认值为 1。

use-duplicate-detection

群集连接使用网桥来链接代理,而网桥可以配置为在每个被转发的消息中添加重复的 ID 属性。如果网桥的目标代理崩溃,然后恢复信息,则可以从源代理重新发送消息。通过将 use-duplicate-detection 设置为 true,将过滤掉任何重复的消息,并在目标代理接收时忽略。默认值是 true

附录 D. 命令行工具

AMQ Broker 包括了一组命令行界面(CLI)工具,以便您可以管理您的消息传递日志。下表列出了各个工具的名称及其描述。

工具描述

exp

使用特殊和独立的 XML 格式导出消息数据。

imp

使用由 exp 提供的输出,将日志导入到正在运行的代理。

data

打印关于日志记录报告及其数据压缩。

encode

显示被编码为 String 的日志的内部格式。

decode

从编码中导入内部日志格式。

如需每一工具可用命令的完整列表,请使用 help 参数以及工具的名称。在以下示例中,CLI 输出列出了用户在输入命令 ./artemis 帮助数据后数据 工具的所有可用命令。

$ ./artemis help data

NAME
        artemis data - data tools group
        (print|imp|exp|encode|decode|compact) (example ./artemis data print)

SYNOPSIS
        artemis data
        artemis data compact [--broker <brokerConfig>] [--verbose]
                [--paging <paging>] [--journal <journal>]
                [--large-messages <largeMessges>] [--bindings <binding>]
        artemis data decode [--broker <brokerConfig>] [--suffix <suffix>]
                [--verbose] [--paging <paging>] [--prefix <prefix>] [--file-size <size>]
                [--directory <directory>] --input <input> [--journal <journal>]
                [--large-messages <largeMessges>] [--bindings <binding>]
        artemis data encode [--directory <directory>] [--broker <brokerConfig>]
                [--suffix <suffix>] [--verbose] [--paging <paging>] [--prefix <prefix>]
                [--file-size <size>] [--journal <journal>]
                [--large-messages <largeMessges>] [--bindings <binding>]
        artemis data exp [--broker <brokerConfig>] [--verbose]
                [--paging <paging>] [--journal <journal>]
                [--large-messages <largeMessges>] [--bindings <binding>]
        artemis data imp [--host <host>] [--verbose] [--port <port>]
                [--password <password>] [--transaction] --input <input> [--user <user>]
        artemis data print [--broker <brokerConfig>] [--verbose]
                [--paging <paging>] [--journal <journal>]
                [--large-messages <largeMessges>] [--bindings <binding>]

COMMANDS
        With no arguments, Display help information

        print
            Print data records information (WARNING: don't use while a
            production server is running)

        ...

您可以在工具中使用帮助,了解如何执行各个工具的命令的更多信息。例如,CLI 会在用户进入 ./artemis 帮助 数据打印 后列出有关 data print 的更多信息。

$ ./artemis help data print

NAME
        artemis data print - Print data records information (WARNING: don't use
        while a production server is running)

SYNOPSIS
        artemis data print [--bindings <binding>] [--journal <journal>]
                [--paging <paging>]

OPTIONS
        --bindings <binding>
            The folder used for bindings (default ../data/bindings)

        --journal <journal>
            The folder used for messages journal (default ../data/journal)

        --paging <paging>
            The folder used for paging (default ../data/paging)

附录 E. 消息传递日志配置元素

下表列出了与 AMQ Broker 消息传递日志相关的所有配置元素。

表 E.1. 地址设置元素

Name描述

journal-directory

消息日志所在的目录。默认值为 BROKER_INSTANCE_DIR/data/journal

为了获得最佳性能,日志应位于其自己的物理卷上,以便最小化磁盘头移动。如果日志位于与其他可以写入其他文件(如绑定日志、数据库或事务协调器)共享的卷上,那么磁盘头可能会在这些文件间快速移动,从而大大降低性能。

在使用 SAN 时,应当为每个日志实例提供自己的 LUN(逻辑单元)。

create-journal-dir

如果设置为 true,则日志目录会在 journal-directory 中指定的位置(如果它尚不存在)上自动创建。默认值为 true

journal-type

有效值为 NIOASYNCIO

如果设置为 NIO,代理使用 Java NIO 接口到其日志。设置为 ASYNCIO,代理将使用 Linux 异步 IO 日志。如果您选择 ASYNCIO 但没有运行 Linux,或者您没有安装 libaio,则代理将检测到它,并自动回退到使用 NIO

journal-sync-transactional

如果设置为 true,代理会将所有事务数据刷新事务边界上的磁盘(即提交、准备和回滚)。默认值为 true

journal-sync-non-transactional

如果设置为 true,代理会在每次将非事务消息数据(发送和确认)刷新到磁盘。默认值为 true

journal-file-size

每个日志文件的大小(以字节为单位)。默认值为 10485760 字节 (10MiB)。

journal-min-files

启动时代理预先创建的文件的最小数量。只有不存在消息数据时预先创建文件。

根据您队列要包含的数据量处于 steady 状态,您应该调整这数量的文件以匹配预期的数据总量。

journal-pool-files

系统将根据需要创建任意数量的文件;但是,当回收文件时,它将缩小到 journal-pool-files

默认值为 -1,这意味着在创建后永远不会删除日志中的文件。但是,系统会无法无限地增加,因为您仍需要为可能无限期增长的目的地使用分页。

journal-max-io

控制一次可在 IO 队列中的最大写入请求数。如果队列已满,那么写入将阻止,直到空间释放为止。

在使用 NIO 时,此值应始终为 1。在使用 AIO 时,默认值为 500。最大 AIO 总数不能高于操作系统级别设置的值(/proc/sys/fs/aio-max-nr),通常是 65536。

journal-buffer-timeout

控制缓冲区何时刷新的超时时间。AIO 通常消耗比 NIO 较高的刷新率,因此系统为 NIO 和 AIO 维护不同的默认值。

NIO 的默认值为 3333333 纳秒,或每秒 300 次,AIO 的默认值为 50000 纳秒,或者 2000 秒。

注意

通过增加超时值,您可以将系统吞吐量提高延迟费用,因为选择默认值以在吞吐量和延迟之间达到合理的平衡。

journal-buffer-size

AIO 上时间缓冲区的大小。默认值为 490KiB

journal-compact-min-files

代理压缩日志前所需的文件数量最少。紧凑算法只有在您至少有一个 journal-compact-min-files 时才会启动。默认值为 10

注意

将值设为 0 将禁用紧凑,并可能具有危险,因为日志可能会无限期地增加。

journal-compact-percentage

开始紧凑的阈值。如果日志数据小于 journal-compact-percentage,则会压缩日志数据,以便获得实时数据。另请注意,在日志中至少有 journal-compact-min-files 数据文件后,压缩将无法启动。默认值为 30

附录 F. 复制高可用性配置元素

下表列出了使用复制 HA 策略时有效的 ha-policy 配置元素。

表 F.1. 使用复制高可用性时可用的配置元素

Name描述

check-for-live-server

只适用于配置为 master 代理的代理。指定原始 master 代理在启动时是否使用自己的服务器 ID 检查集群是否有另一个实时代理。设置为 true 以恢复原始 master 代理,并避免出现两个代理同时处于"脑裂"的情况。这个属性的默认值为 false

cluster-name

用于复制的集群配置的名称。只有在配置多个集群连接时,才需要此设置。如果配置,则在连接到集群时使用此名称进行集群配置。如果未设置,则使用配置中定义的第一个集群连接。

group-name

如果设置,备份代理仅与具有 group-name 值的 live 代理配对。

initial-replication-sync-timeout

在完成副本的初始复制过程后,复制代理将等待的时间,以确认它收到了所有必要的数据。这个属性的默认值为 30,000 毫秒。

注意

在这个时间段内,其他与日志相关的操作都会被阻断。

max-saved-replicated-journals-size

只适用于备份代理。指定备份代理保留的备份日志文件数量。达到这个值后,代理通过删除最旧的日志文件为每个新备份文件腾出空间。此属性的默认值为 2

allow-failback

只适用于备份代理。决定当另一个代理(如 live 代理)发出请求时,备份代理是否恢复其原始角色。这个属性的默认值为 true

restart-backup

只适用于备份代理。决定备份代理在返回到另一个代理失败后是否自动重启。这个属性的默认值为 true

修订 2022-10-22 21:07:50 +1000