第 6 章 网络连接
6.1. 自动故障切换 复制链接链接已复制到粘贴板!
客户端可以接收所有 master 和从代理的信息,以便在连接失败时可以重新连接到从代理。然后从代理会在故障转移前自动重新创建每个连接上存在的任何会话和消费者。此功能使您不必在应用程序中手动编码重新连接逻辑。
在从卷上重新创建会话时,它不知道已经发送或确认的消息。故障切换时的任何内部发送或确认也可能丢失。但是,即便没有透明故障转移,也很容易通过将重复检测和重试事务结合使用,保证 一次并仅 一次交付一次(即便在故障的情况下也是如此)。
当客户端没有在可配置的时间段内从代理接收数据包时,客户端会检测到连接失败。如需更多信息,请参阅 第 6.3 节 “检测死连接”。
您有多种方法可将客户端配置为接收关于主从和从设备的信息。种选择是将客户端配置为连接到特定代理,然后接收集群中其他代理的信息。如需更多信息,请参阅 第 6.7 节 “配置静态发现”。但是,最常见的方法是使用 代理发现。有关如何配置代理发现的详情请参考 第 6.6 节 “配置动态发现”。
另外,您可以通过在用于连接到代理的 URI 的查询字符串中添加参数来配置客户端,如下例所示。
connectionFactory.ConnectionFactory=tcp://localhost:61616?ha=true&reconnectAttempts=3
connectionFactory.ConnectionFactory=tcp://localhost:61616?ha=true&reconnectAttempts=3
流程
要使用查询字符串配置客户端进行故障转移,请确保正确设置了 URI 的以下组件:
-
URI 的
host:port部分必须指向正确配置了备份的 master 代理。此主机和端口仅用于初始连接。host:port值与实时和备份服务器之间的实际连接故障切换无关。在上例中,localhost:61616用于host:port。 (可选)要使用多个代理作为可能的初始连接,对
host:port条目进行分组,如下例所示:connectionFactory.ConnectionFactory=(tcp://host1:port,tcp://host2:port)?ha=true&reconnectAttempts=3
connectionFactory.ConnectionFactory=(tcp://host1:port,tcp://host2:port)?ha=true&reconnectAttempts=3Copy to Clipboard Copied! Toggle word wrap Toggle overflow -
包含 name-value 对
ha=true作为查询字符串的一部分,以确保客户端接收集群中每个 master 和 slave 代理的信息。 -
包含 name-value 对
reconnectAttempts=n,其中n是一个大于 0 的整数。这个参数设置客户端试图重新连接到代理的次数。
只有在 ha=true 和 reconnectAttempts 大于 0 时才会发生故障切换。另外,客户端还必须与 master 代理进行初始连接,以便接收有关其他代理的信息。如果初始连接失败,客户端只能重试来建立它。如需更多信息,请参阅 第 6.1.1 节 “在初始连接中切换失败”。
6.1.1. 在初始连接中切换失败 复制链接链接已复制到粘贴板!
由于客户端直到第一次连接到 HA 集群后才会收到每个代理的信息,因此有一个时间窗口,客户端只能连接到连接 URI 中包含的代理。因此,如果初始连接期间发生故障,客户端无法切换到其他 master 代理,只能尝试重新建立初始连接。可以为一组重新连接尝试数配置客户端。尝试次数之后,将引发异常。
设置重新连接尝试数
以下示例演示了如何使用 AMQ 核心协议 JMS 客户端将重新连接尝试数设置为 3。默认值为 0,即,只尝试一次。
流程
通过将值传递给 ServerLocator.setInitialConnectAttempts() 来设置重新连接尝试的数量。
ConnectionFactory cf = ActiveMQJMSClient.createConnectionFactory(...) cf.setInitialConnectAttempts(3);
ConnectionFactory cf = ActiveMQJMSClient.createConnectionFactory(...)
cf.setInitialConnectAttempts(3);
设置全局重新连接尝试数
另外,您可以为代理配置中的最大重新连接尝试数应用全局值。最大值将应用到所有客户端连接。
流程
通过添加 initial-connect-attempts 配置元素并为生存时间提供值来编辑 <broker-instance-dir>/etc/broker.xml,如下例所示。
- 1
- 所有连接到代理的客户端最多允许 3 个尝试重新连接。默认值为 -1,它允许客户端无限尝试。
6.1.2. 在故障转移期间处理阻塞调用 复制链接链接已复制到粘贴板!
当发生故障转移时,客户端正在等待代理的响应继续执行,新创建的会话不知道该调用正在进行中。否则,初始调用可能会永远挂起,等待绝不会发出的响应。为防止这种情况,代理被设计为通过抛出异常来取消阻止任何在故障转移时正在进行中的调用。客户端代码可以捕获这些异常,并在需要时重试任何操作。
使用 AMQ 核心协议 JMS 客户端时,如果未阻塞的方法是调用 commit() 或 prepare(),则会自动回滚事务,代理抛出异常。
6.1.3. 使用事务处理故障转移 复制链接链接已复制到粘贴板!
使用 AMQ 核心协议 JMS 客户端时,如果会话是事务性的,并且消息已在当前事务中发送或确认,代理无法确定这些消息或者在故障转移过程中丢失了这些消息。因此,事务被标记为回滚。任何后续尝试提交它都会抛出 javax.jms.TransactionRolledBackException。
应注意此规则何时使用 XA。如果使用了两阶段提交并且调用了 prepare(),回滚可能会导致 HeuristicMixedException。因此,提交会引发 XAException.XA_RETRY 异常,它会通知 Transaction Manager 在稍后应重试提交。如果原始提交未发生,则它仍然存在并可提交。如果提交不存在,则假定已提交,但事务管理器可能会记录警告。这个例外的一个副作用是所有非持久性信息都会丢失。为避免此类损失,在使用 XA 时始终使用持久消息。这不是确认问题,因为在调用 prepare() 前,它们会被刷新到代理中。
AMQ 核心协议 JMS 客户端代码必须捕获异常并执行任何必要的客户端侧回滚。不过,不需要回滚会话,因为它已经回滚。然后,用户可以在同一会话中再次重试事务操作。
如果在执行提交调用时发生故障转移,代理会取消阻塞调用,以防止 AMQ 核心协议 JMS 客户端无限期等待响应。因此,在出现故障前,客户端无法确定事务提交是否真正在 master 代理上处理。
为补救这一点,AMQ 核心协议 JMS 客户端可以在事务中启用重复检测,并在未阻塞调用后重试事务操作。如果在故障转移前在 master 代理上成功提交事务,重复检测可确保在代理一侧忽略事务中的任何持久消息。这可防止发送多次消息。
如果会话非事务性,则在故障转移时可能会丢失消息或确认。如果您要为非转换会话 提供一次且仅一次 的保证,请启用重复检测并捕获未阻塞异常。
6.1.4. 收到连接失败通知 复制链接链接已复制到粘贴板!
JMS 提供了一种标准机制,用于获得异步连接失败通知: java.jms.ExceptionListener。
当连接失败时,代理会始终调用 ExceptionListener 或 SessionFailureListener 实例,无论连接是成功通过、重新连接还是重新附加。您可以通过检查 SessionFailureListener 上在 connectionFailed 中传递的 failedOver 标记来找出是否发生了重新连接或重新附加。另外,您可以检查 javax.jms.JMSException 的错误代码,可以是以下之一:
| 错误代码 | 描述 |
|---|---|
| 故障切换 | 故障转移已经发生,代理已成功重新附加或重新连接 |
| 断开连接 | 没有发生故障切换,代理断开连接 |