在本节中,我们将讨论连接生存时间 (TTL) 并解释 Apache ActiveMQ Artemis 如何处理崩溃的客户端和未干净关闭其资源的客户端。

1. 在服务器上清理资源

在 Apache ActiveMQ Artemis 客户端应用程序退出之前,建议使用 finally 块以受控方式关闭其资源。

以下是一个表现良好的核心客户端应用程序在 finally 块中关闭其会话和会话工厂的示例

ServerLocator locator = null;
ClientSessionFactory sf = null;
ClientSession session = null;

try {
   locator = ActiveMQClient.createServerLocatorWithoutHA(..);

   sf = locator.createSessionFactory();

   session = sf.createSession(...);

   ... do some stuff with the session...
} finally {
   if (session != null) {
      session.close();
   }

   if (sf != null) {
      sf.close();
   }

   if(locator != null) {
      locator.close();
   }
}

以下是一个表现良好的 JMS 客户端应用程序的示例

Connection jmsConnection = null;

try {
   ConnectionFactory jmsConnectionFactory = new ActiveMQConnectionFactory("tcp://127.0.0.1:61616");

   jmsConnection = jmsConnectionFactory.createConnection();

   ... do some stuff with the connection...
} finally {
   if (connection != null) {
      connection.close();
   }
}

或者使用 Java 的自动关闭功能,这可以节省几行代码

try (
     ActiveMQConnectionFactory jmsConnectionFactory = new ActiveMQConnectionFactory("tcp://127.0.0.1:61616");
     Connection jmsConnection = jmsConnectionFactory.createConnection()) {
   ... do some stuff with the connection...
}

不幸的是,用户并不总是编写表现良好的应用程序,有时客户端会崩溃,因此它们没有机会清理其资源!

如果发生这种情况,则可能会导致服务器端资源(如会话)挂在服务器上。如果这些资源没有被删除,它们会导致服务器上的资源泄漏,随着时间的推移,这会导致服务器内存或其他资源耗尽。

我们必须在清理失效客户端资源的要求与客户端和服务器之间的网络有时可能会发生故障然后恢复之间取得平衡,从而允许客户端重新连接。Apache ActiveMQ Artemis 支持客户端重新连接,因此我们不想过早地清理“失效”的服务器端资源,否则这将阻止任何客户端重新连接,因为它将无法在服务器上找到其旧会话。

Apache ActiveMQ Artemis 通过连接 TTL 使所有这些都可配置。基本上,TTL 决定了服务器在没有来自客户端的任何数据到达的情况下保持连接存活的时间。客户端将定期自动发送“ping”数据包以防止服务器将其关闭。如果服务器在连接 TTL 时间内没有在连接上接收到任何数据包,它将自动关闭服务器上与该连接相关的所有会话。

连接 TTL 在 URI 上使用 connectionTTL 参数配置。

在“不可靠”连接(例如,使用 tcp URL 方案的 Netty 连接)上,连接 TTL 的默认值为 60000 毫秒,即 1 分钟。在“可靠”连接(例如,使用 vm URL 方案的内存内连接)上,连接 TTL 的默认值为 -1connectionTTL-1 表示服务器永远不会在服务器端超时连接。

如果您不希望客户端能够指定自己的连接 TTL,您可以覆盖服务器端设置的全局值以使用所有值。这可以通过在服务器端配置中指定 connection-ttl-override 属性来完成。connection-ttl-override 的默认值为 -1,表示“不要覆盖”(即,让客户端使用它们自己的值)。

检查连接是否存在 TTL 违规的逻辑会在代理上定期运行。默认情况下,每 2000 毫秒检查一次。但是,如果需要,可以使用 connection-ttl-check-interval 属性更改此值。

2. 关闭遗忘的资源

如前所述,重要的是,在完成对所有核心客户端会话和 JMS 连接的使用后,始终在 finally 块中显式关闭它们。

如果您未能这样做,Apache ActiveMQ Artemis 会在垃圾回收时检测到这一点,并记录一条警告(如果您使用的是 JMS,则警告会涉及 JMS 连接)。

Apache ActiveMQ Artemis 将为您关闭连接/客户端会话。

请注意,日志还会告诉您在用户代码中创建的 JMS 连接/客户端会话的确切行,这些连接/客户端会话后来没有关闭。这将使您能够查明代码中的错误并进行相应的更正。

3. 从客户端检测故障

在上一节中,我们讨论了客户端如何向服务器发送 ping 以及服务器如何清理“失效”的连接资源。ping 还有另一个原因,那就是为了让客户端能够检测到服务器或网络是否发生了故障。

只要客户端从服务器接收数据,它就会认为连接仍然处于活动状态。

如果客户端在可配置的毫秒数内没有接收到任何数据包,它会认为连接已失败,并且会根据其配置方式,要么启动故障转移,要么调用任何 FailureListener 实例(或如果您使用的是 JMS,则调用 ExceptionListener 实例)。

这可以通过在客户端用于连接的 URI 上设置 clientFailureCheckPeriod 参数来控制,例如 tcp://127.0.0.1:61616?clientFailureCheckPeriod=30000

在“不可靠”连接(例如,Netty 连接)上,客户端故障检查周期的默认值为 30000 毫秒,即 30 秒。在“可靠”连接(例如,内存内连接)上,客户端故障检查周期的默认值为 -1。值为 -1 表示如果从服务器没有接收到数据,客户端永远不会在客户端端使连接失败。通常,这远低于连接 TTL,以允许客户端在瞬态故障的情况下重新连接。

4. 配置异步连接执行

在服务器端接收的大多数数据包都在远程线程上执行。这些数据包代表短时间运行的操作,并且出于性能原因始终在远程线程上执行。

但是,默认情况下,某些类型的数据包使用线程池中的线程执行,以便远程线程不会被占用太长时间。请注意,在另一个线程上异步处理操作会增加一些延迟。这些数据包是

  • org.apache.activemq.artemis.core.protocol.core.impl.wireformat.RollbackMessage

  • org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionCloseMessage

  • org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionCommitMessage

  • org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionXACommitMessage

  • org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionXAPrepareMessage

  • org.apache.activemq.artemis.core.protocol.core.impl.wireformat.SessionXARollbackMessage

要禁用异步连接执行,请在 broker.xml 中将参数 async-connection-execution-enabled 设置为 false(默认值为 true)。