脑裂 是指两个不同的代理同时为相同的消息提供服务的情况。当这种情况发生时,客户端应用程序不会像预期的那样共享同一个 代理,而是可能会被分成两个脑裂代理之间。这会导致问题,因为会导致

  • 重复消息 例如,当同一个 JMS 队列上的多个消费者被分成两个代理并接收相同的消息时

  • 丢失消息 例如,当同一个 JMS 主题上的多个消费者被分成两个代理,而生产者只向其中一个代理发送消息时

脑裂最常发生在 HA 复制 配置中的两个代理对之间复制连接丢失时。当此连接丢失时,备份会假定主代理已死,因此会激活。此时,网络上有两个彼此隔离的代理,因为备份有主代理所有消息的副本,因此它们都在提供相同的消息。

共享存储配置呢?

虽然在 HA 共享存储 配置中的代理对之间发生脑裂在技术上是可能的,但它需要存储设备的文件锁定机制发生故障,而代理共享该存储设备。

使用共享存储的好处之一是,存储设备本身充当仲裁器,以确保一致性并减轻脑裂。

从脑裂中恢复可能很简单,只需停止错误激活的代理即可。但是,此解决方案只有在没有客户端应用程序连接到它并执行消息操作的情况下才有效。允许客户端应用程序与脑裂代理交互的时间越长,理解和修复由此产生的问题就越困难。

您可以选择几种不同的配置来帮助减轻脑裂。

1. 可插拔锁管理器

可插拔锁管理器配置要求第三方在主代理和备份代理之间建立共享锁。共享锁确保主代理或备份代理在任何给定时间都处于活动状态,类似于共享存储用例中的文件锁功能。

插件 决定使用哪个第三方实现。它可以像支持锁定的网络文件系统上的共享文件一样简单(例如 NFS),也可以像 etcd 这样更复杂。

该代理附带一个基于 Apache ZooKeeper参考插件实现,这是一个用于此类任务的通用实现。

可插拔锁管理器的主要好处是它释放了代理建立可靠投票的责任。这意味着单个 HA 代理对可以可靠地防止脑裂。

2. 法定人数投票

法定人数投票是一个过程,通过该过程,集群中的一个节点可以在不直接与该节点通信的情况下确定集群中另一个节点是否处于活动状态。然后,启动投票的代理可以根据结果采取行动(例如,关闭自身以避免脑裂)。

法定人数投票需要集群中其他活动 代理的参与。当然,这需要集群中确实存在其他活动代理,这意味着法定人数投票不适用于单个 HA 代理对。此外,它也不适用于只有两个 HA 代理对,因为这还不够成法定人数。必须至少有三个 HA 代理对才能使用法定人数投票建立适当的法定人数。

2.1. 投票机制

当主代理和备份之间的复制连接丢失时,备份和/或主代理可能会启动投票。

要通过投票,需要大多数 赞成票。例如,在 3 节点集群中,投票将通过 2 票赞成。对于 4 节点集群,这将是 3 票赞成,依此类推。

2.1.1. 备份投票

默认情况下,如果备份丢失了与主代理的复制连接,它将自动激活。但是,可以通过 vote-on-replication-failure 属性进行配置,以启动法定人数投票,以决定是否激活。如果这样做,则备份将继续投票,直到它收到允许它启动的投票,或者它检测到主代理仍然处于活动状态。在后一种情况下,它将重新启动为备份。

有关配置的更多详细信息,请参见有关 复制配置 的部分。

2.1.2. 主代理投票

默认情况下,如果主服务器丢失了与备份的复制连接,它将继续运行并等待备份重新连接并重新开始复制。但是,这可能意味着主代理仍然处于活动状态,即使备份已激活,因此此行为可以通过 vote-on-replication-failure 属性进行配置。

有关配置的更多详细信息,请参见有关 复制配置 的部分。

3. 网络ping测试

您可以在 broker.xml 中配置一个或多个地址,这些地址将在服务器的整个生命周期中被ping测试。如果服务器无法ping测试列表中的一个或多个地址,它将停止自身。

如果您使用 --ping 参数执行 create 命令,您将创建一个默认的 XML,该 XML 可以与网络检查一起使用。

$ ./artemis create /myDir/myServer --ping 10.0.0.1

此 XML 将添加到您的 broker.xml 中。

<!--
  You can verify the network health of a particular NIC by specifying the <network-check-NIC> element.
   <network-check-NIC>theNicName</network-check-NIC>
  -->

<!--
  Use this to use an HTTP server to validate the network
   <network-check-URL-list>http://www.apache.org</network-check-URL-list> -->

<network-check-period>10000</network-check-period>
<network-check-timeout>1000</network-check-timeout>

<!-- this is a comma separated list, no spaces, just DNS or IPs
     it should accept IPV6

     Warning: Make sure you understand your network topology as this is meant to check if your network is up.
              Using IPs that could eventually disappear or be partially visible may defeat the purpose.
              You can use a list of multiple IPs, any successful ping will make the server OK to continue running -->
<network-check-list>10.0.0.1</network-check-list>

<!-- use this to customize the ping used for ipv4 addresses -->
<network-check-ping-command>ping -c 1 -t %d %s</network-check-ping-command>

<!-- use this to customize the ping used for ipv6 addresses -->
<network-check-ping6-command>ping6 -c 1 %2$s</network-check-ping6-command>

一旦您在给定的示例中丢失了与 10.0.0.1 的连接,代理将记录类似于以下内容的信息

09:49:24,562 WARN  [org.apache.activemq.artemis.core.server.NetworkHealthCheck] Ping Address /10.0.0.1 wasn't reacheable
09:49:36,577 INFO  [org.apache.activemq.artemis.core.server.NetworkHealthCheck] Network is unhealthy, stopping service ActiveMQServerImpl::serverUUID=04fd5dd8-b18c-11e6-9efe-6a0001921ad0
09:49:36,625 INFO  [org.apache.activemq.artemis.core.server] AMQ221002: Apache ActiveMQ Artemis Message Broker version 1.6.0 [04fd5dd8-b18c-11e6-9efe-6a0001921ad0] stopped, uptime 14.787 seconds
09:50:00,653 WARN  [org.apache.activemq.artemis.core.server.NetworkHealthCheck] ping: sendto: No route to host
09:50:10,656 WARN  [org.apache.activemq.artemis.core.server.NetworkHealthCheck] Host is down: java.net.ConnectException: Host is down
	at java.net.Inet6AddressImpl.isReachable0(Native Method) [rt.jar:1.8.0_73]
	at java.net.Inet6AddressImpl.isReachable(Inet6AddressImpl.java:77) [rt.jar:1.8.0_73]
	at java.net.InetAddress.isReachable(InetAddress.java:502) [rt.jar:1.8.0_73]
	at org.apache.activemq.artemis.core.server.NetworkHealthCheck.check(NetworkHealthCheck.java:295) [artemis-commons-1.6.0-SNAPSHOT.jar:1.6.0-SNAPSHOT]
	at org.apache.activemq.artemis.core.server.NetworkHealthCheck.check(NetworkHealthCheck.java:276) [artemis-commons-1.6.0-SNAPSHOT.jar:1.6.0-SNAPSHOT]
	at org.apache.activemq.artemis.core.server.NetworkHealthCheck.run(NetworkHealthCheck.java:244) [artemis-commons-1.6.0-SNAPSHOT.jar:1.6.0-SNAPSHOT]
	at org.apache.activemq.artemis.core.server.ActiveMQScheduledComponent$2.run(ActiveMQScheduledComponent.java:189) [artemis-commons-1.6.0-SNAPSHOT.jar:1.6.0-SNAPSHOT]
	at org.apache.activemq.artemis.core.server.ActiveMQScheduledComponent$3.run(ActiveMQScheduledComponent.java:199) [artemis-commons-1.6.0-SNAPSHOT.jar:1.6.0-SNAPSHOT]
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [rt.jar:1.8.0_73]
	at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) [rt.jar:1.8.0_73]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) [rt.jar:1.8.0_73]
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) [rt.jar:1.8.0_73]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [rt.jar:1.8.0_73]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [rt.jar:1.8.0_73]
	at java.lang.Thread.run(Thread.java:745) [rt.jar:1.8.0_73]

一旦您重新建立了与配置的检查列表的网络连接

09:53:23,461 INFO  [org.apache.activemq.artemis.core.server.NetworkHealthCheck] Network is healthy, starting service ActiveMQServerImpl::
09:53:23,462 INFO  [org.apache.activemq.artemis.core.server] AMQ221000: primary Message Broker is starting with configuration Broker Configuration (clustered=false,journalDirectory=./data/journal,bindingsDirectory=./data/bindings,largeMessagesDirectory=./data/large-messages,pagingDirectory=./data/paging)
09:53:23,462 INFO  [org.apache.activemq.artemis.core.server] AMQ221013: Using NIO Journal
09:53:23,462 INFO  [org.apache.activemq.artemis.core.server] AMQ221043: Protocol module found: [artemis-server]. Adding protocol support for: CORE
09:53:23,463 INFO  [org.apache.activemq.artemis.core.server] AMQ221043: Protocol module found: [artemis-amqp-protocol]. Adding protocol support for: AMQP
09:53:23,463 INFO  [org.apache.activemq.artemis.core.server] AMQ221043: Protocol module found: [artemis-hornetq-protocol]. Adding protocol support for: HORNETQ
09:53:23,463 INFO  [org.apache.activemq.artemis.core.server] AMQ221043: Protocol module found: [artemis-mqtt-protocol]. Adding protocol support for: MQTT
09:53:23,464 INFO  [org.apache.activemq.artemis.core.server] AMQ221043: Protocol module found: [artemis-openwire-protocol]. Adding protocol support for: OPENWIRE
09:53:23,464 INFO  [org.apache.activemq.artemis.core.server] AMQ221043: Protocol module found: [artemis-stomp-protocol]. Adding protocol support for: STOMP
09:53:23,541 INFO  [org.apache.activemq.artemis.core.server] AMQ221003: Deploying queue jms.queue.DLQ
09:53:23,541 INFO  [org.apache.activemq.artemis.core.server] AMQ221003: Deploying queue jms.queue.ExpiryQueue
09:53:23,549 INFO  [org.apache.activemq.artemis.core.server] AMQ221020: Started Acceptor at 0.0.0.0:61616 for protocols [CORE,MQTT,AMQP,STOMP,HORNETQ,OPENWIRE]
09:53:23,550 INFO  [org.apache.activemq.artemis.core.server] AMQ221020: Started Acceptor at 0.0.0.0:5445 for protocols [HORNETQ,STOMP]
09:53:23,554 INFO  [org.apache.activemq.artemis.core.server] AMQ221020: Started Acceptor at 0.0.0.0:5672 for protocols [AMQP]
09:53:23,555 INFO  [org.apache.activemq.artemis.core.server] AMQ221020: Started Acceptor at 0.0.0.0:1883 for protocols [MQTT]
09:53:23,556 INFO  [org.apache.activemq.artemis.core.server] AMQ221020: Started Acceptor at 0.0.0.0:61613 for protocols [STOMP]
09:53:23,556 INFO  [org.apache.activemq.artemis.core.server] AMQ221007: Server is now active
09:53:23,556 INFO  [org.apache.activemq.artemis.core.server] AMQ221001: Apache ActiveMQ Artemis Message Broker version 1.6.0 [0.0.0.0, nodeID=04fd5dd8-b18c-11e6-9efe-6a0001921ad0]

确保您了解您的网络拓扑,因为这是为了验证您的网络。使用最终可能消失或部分可见的 IP 可能违背了目的。您可以使用多个 IP 列表。任何成功的 ping 测试都将使服务器可以继续运行