网络故障后,RabbitMQ群集未重新连接

时间:2011-12-28 09:28:04

标签: cluster-computing rabbitmq

我有RabbitMQ集群,其中有两个节点正在生产中,集群正在打破这些错误消息:

  

=错误报告==== 2011年12月23日:: 04:21:34 ===
  **节点兔子@ rabbitmq02没有回复**
  **删除(超时)连接**

     

= INFO REPORT ==== 23-Dec-2011 :: 04:21:35 ===
  节点兔子@ rabbitmq02失去了'兔子'

     

=错误报告==== 2011年12月23日:: 04:21:49 ===
  Mnesia(兔子@ rabbitmq01):**错误** mnesia_event得到{inconsistent_database,running_partitioned_network,rabbit @ rabbitmq02}

我试图通过使用“tcpkill”终止两个节点之间的连接来模拟问题,群集已断开连接,并且令人惊讶的是两个节点没有尝试重新连接!

当群集中断时,haproxy负载均衡器仍然将两个节点标记为活动并向两个节点发送请求,尽管它们不在群集中。

我的问题:

  1. 如果节点配置为群集,当我遇到网络故障时,他们为什么不尝试重新连接?

  2. 如何识别损坏的群集并关闭其中一个节点?分别使用两个节点时,我遇到了一致性问题。

3 个答案:

答案 0 :(得分:13)

RabbitMQ集群在不可靠的网络上运行不佳(RabbitMQ文档的一部分)。因此,当网络故障发生时(在双节点集群中),每个节点都认为它是集群中的主节点和唯一节点。两个主节点不会自动重新连接,因为它们的状态不会自动同步(即使在RabbitMQ从站的情况下 - 实际的消息同步也不会发生 - 从站只是“赶上”消息从队列中消耗掉并且消息更多得到补充)。

要检测群集是否已损坏,请运行命令:

rabbitmqctl cluster_status

在构成群集一部分的每个节点上。如果群集中断,那么您将只看到一个节点。类似的东西:

Cluster status of node rabbit@rabbitmq1 ...
[{nodes,[{disc,[rabbit@rabbitmq1]}]},{running_nodes,[rabbit@rabbitmq1]}]
...done.

在这种情况下,您需要在构成原始群集一部分的其中一个节点上运行以下命令集(以便它作为从属连接到群集中的另一个主节点(例如rabbitmq1)) :

rabbitmqctl stop_app

rabbitmqctl reset

rabbitmqctl join_cluster rabbit@rabbitmq1

rabbitmqctl start_app

最后再次检查群集状态..这次你应该看到两个节点。

注意:如果您使用虚拟IP在HA配置中使用RabbitMQ节点(并且客户端使用此虚拟IP连接到RabbitMQ),那么应该成为主节点的节点应该是具有虚拟IP的节点IP

答案 1 :(得分:9)

从这种故障中恢复的另一种方法是使用Mnesia,这是RabbitMQ用作持久性机制的数据库,RabbitMQ实例的同步(以及主/从状态)由此控制。有关所有详细信息,请参阅以下网址:http://www.erlang.org/doc/apps/mnesia/Mnesia_chap7.html

在此处添加相关部分:

  

有几种情况,Mnesia可能会检测到该网络   由于通信失败而被分区。

     

其中一个是当Mnesia已经启动并运行并且Erlang节点获益时   再次联系。然后Mnesia将尝试联系Mnesia   节点,看它是否也认为网络已被分区   一阵子。如果两个节点上的Mnesia都记录了mnesia_down条目   相互之间,Mnesia会生成一个名为的系统事件   {inconsistent_database,running_partitioned_network,Node}就是这样   发送给Mnesia的事件处理程序和其他可能的订阅者。该   默认事件处理程序向错误记录器报告错误。

     

Mnesia可能会发现网络已经发现的另一个场合   由于通信故障而被分区,是在启动时。如果是Mnesia   检测到本地节点和另一个节点都收到了mnesia_down   彼此之间生成{inconsistent_database,   starting_partitioned_network,Node}系统事件并按照描述行事   上方。

     

如果应用程序检测到通信失败   这可能导致数据库不一致,可能会使用   函数mnesia:set_master_nodes(Tab,Nodes)来精确定位   节点可以加载每个表。

     

启动时,Mnesia的普通表加载算法将被绕过并且   该表将从为其定义的一个主节点加载   表,不管日志中潜在的mnesia_down条目。该   节点可能只包含表具有副本的节点以及它是否具有副本   是空的,特定表的主节点恢复机制   将被重置,并在下次使用正常的加载机制   重新启动。

     

函数mnesia:set_master_nodes(Nodes)为所有人设置主节点   表。对于每个表,它将确定其副本节点并调用   mnesia:set_master_nodes(Tab,TabNodes)与那些副本节点   包含在节点列表中(即TabNodes是   节点和表的副本节点)。如果交叉点是   清空特定表的主节点恢复机制   重置,正常加载机制将在下次重启时使用。

     

函数mnesia:system_info(master_node_tables)和   mnesia:table_info(Tab,master_nodes)可用于获取信息   关于潜在的主节点。

     

确定通信失败后要保留哪些数据   Mnesia的范围。一种方法是确定哪个“岛屿”   包含大多数节点。使用{majority,true}选项   关键表可以是确保不属于的节点的一种方法   “多数岛屿”无法更新这些表格。注意   这构成了少数民族节点服务的减少。这个   将是一种有利于更高一致性保证的权衡。

     

函数mnesia:force_load_table(Tab)可用于强制加载   无论激活哪种表加载机制,都可以使用该表。

这是一种从这种故障中恢复的更长时间和更复杂的方法..但会提供更好的粒度和对最终主节点中应该可用的数据的控制(这可以减少可能的数据丢失量)在“合并”RabbitMQ主人时发生。)

答案 2 :(得分:8)

RabbitMQ还提供了两种自动处理网络分区的方法:暂停 - 少数模式和自动恢复模式。 (默认行为称为忽略模式)。

在pause-minority模式下,RabbitMQ将自动暂停群集节点,这些节点在看到其他节点发生故障后确定自己处于少数(即,少于或等于节点总数的一半)。因此,它从CAP定理中选择可用性的分区容差。这确保了在网络分区的情况下,单个分区中的节点最多将继续运行。

在autoheal模式下,如果认为分区已经发生,RabbitMQ将自动决定获胜分区。它将重新启动不在获胜分区中的所有节点。获胜分区是拥有最多分区的分区 自动处理分区连接的客户端(或者如果这会产生一个绘图,那个节点数最多的那个;如果仍然产生一个绘图,那么将以未指定的方式选择其中一个分区。)

您可以通过将配置文件中Rabbit应用程序的配置参数cluster_partition_handling设置为pause_minorityautoheal来启用任一模式。

我应该选择哪种模式?

了解允许RabbitMQ自动处理网络分区并不会减少问题,这一点非常重要。网络分区总是会导致RabbitMQ集群出现问题;你只是对你得到的问题有了一定程度的选择。如简介中所述,如果您想通过普遍不可靠的链接连接RabbitMQ集群,则应使用federation plugin or the shovel plugin

话虽如此,您可能希望选择恢复模式,如下所示:

  • 忽略:您的网络确实可靠。您的所有节点都在机架中,与交换机连接,该交换机也是通往外部世界的路径。如果任何其他群集发生故障(或者您有一个双节点群集),则不希望运行任何群集关闭的任何风险。

  • pause_minority:您的网络可能不太可靠。您已在EC2中跨3个AZ聚集,并且您假设一次只有一个AZ会失败。在那种情况下,您希望剩余的两个AZ继续工作,并且失败的AZ中的节点会自动重新加入,并且当AZ返回时不会大惊小怪。

  • autoheal:您的网络可能不可靠。您更关注服务的连续性而不是数据完整性。您可能有一个双节点集群。

这个答案来自rabbitmq docs。 https://www.rabbitmq.com/partitions.html会为您提供更详细的说明。