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

Ran*_*nch 14 cluster-computing rabbitmq

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

= ERROR REPORT ==== 23-Dec-2011 ::
04:21:34 ===**节点兔子@ rabbitmq02没有响应**
**删除(超时)连接**

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

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

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

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

我的问题:

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

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

Gur*_*dal 14

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

要检测是否有损坏的群集,请运行以下命令:

rabbitmqctl cluster_status
Run Code Online (Sandbox Code Playgroud)

在构成群集一部分的每个节点上.如果群集中断,那么您将只看到一个节点.就像是:

Cluster status of node rabbit@rabbitmq1 ...
[{nodes,[{disc,[rabbit@rabbitmq1]}]},{running_nodes,[rabbit@rabbitmq1]}]
...done.
Run Code Online (Sandbox Code Playgroud)

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

rabbitmqctl stop_app

rabbitmqctl reset

rabbitmqctl join_cluster rabbit@rabbitmq1

rabbitmqctl start_app
Run Code Online (Sandbox Code Playgroud)

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

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


Gur*_*dal 9

另一种从这种故障中恢复的方法是使用Mnesia,它是RabbitMQ用作持久性机制的数据库,RabbitMQ实例的同步(以及主/从状态)由此控制.有关所有详细信息,请参阅以下URL: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时可能发生的数据丢失量)大师).


New*_*one 9

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

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

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

您可以通过设置配置参数启用这两种模式下cluster_partition_handling在配置文件中的兔应用程序要么pause_minorityautoheal.

我应该选择哪种模式?

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

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

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

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

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

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