【问题标题】:RabbitMQ cluster is not reconnecting after network failure网络故障后 RabbitMQ 集群未重新连接
【发布时间】:2012-01-29 01:21:18
【问题描述】:

我有一个带有两个生产节点的 RabbitMQ 集群,集群因以下错误消息而中断:

=ERROR REPORT==== 23-Dec-2011::04:21:34 ===
** Node rabbit@rabbitmq02 not responding **
** Removing (timedout) connection **

=INFO REPORT==== 23-Dec-2011::04:21:35 ===
node rabbit@rabbitmq02 lost 'rabbit'

=ERROR REPORT==== 23-Dec-2011::04:21:49 ===
Mnesia(rabbit@rabbitmq01): ** ERROR ** mnesia_event got {inconsistent_database, running_partitioned_network, rabbit@rabbitmq02}

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

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

我的问题:

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

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

【问题讨论】:

    标签: cluster-computing rabbitmq


    【解决方案1】:

    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
    

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

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

    【讨论】:

    • 是否可以将节点配置为在网络再次可用时自动同步其状态?
    • 据我所知(除非在较新版本的 RabbitMQ 中可用...我至少有一年没检查了)。
    【解决方案2】:

    来自 RabbitMQ 文档:Clustering and Network Partitions

    RabbitMQ 还有三种自动处理网络分区的方式:pause-minority 模式、pause-if-all-down 模式和autoheal 模式。默认行为称为ignore 模式。

    在 pause-minority 模式下,RabbitMQ 会在看到其他节点关闭后自动暂停确定自己处于少数(即少于或等于节点总数的一半)的集群节点。因此,它从 CAP 定理中选择分区容差而不是可用性。这确保了在发生网络分区的情况下,最多单个分区中的节点将继续运行。少数节点将在分区开始时暂停,并在分区结束时重新开始。此配置可防止脑裂,因此能够自动从网络分区中恢复而不会出现不一致。

    在 pause-if-all-down 模式下,RabbitMQ 将自动暂停无法到达任何列出的节点的集群节点。换句话说,所有列出的节点都必须关闭,RabbitMQ 才能暂停集群节点。这接近于暂停少数模式,但是,它允许管理员决定首选哪些节点,而不是依赖于上下文。例如,如果集群由机架 A 中的两个节点和机架 B 中的两个节点组成,并且机架之间的链接丢失,则暂停少数模式将暂停所有节点。在 pause-if-all-down 模式下,如果管理员列出了机架 A 中的两个节点,则只有机架 B 中的节点会暂停。请注意,列出的节点可能会在分区的两侧分裂:在这种情况下,没有节点会暂停。这就是为什么有一个额外的 ignore/autoheal 参数来指示如何从分区中恢复。

    在自动修复模式下,如果分区被认为已经发生,RabbitMQ 将自动决定获胜分区,并将重新启动所有不在获胜分区中的节点。与 pause_minority 模式不同,它在分区结束时生效,而不是在分区开始时生效。

    获胜的分区是连接的客户端最多的分区(或者如果这产生平局,则具有最多节点的分区;如果仍然产生平局,则以未指定的方式选择其中一个分区)。

    您可以通过将配置文件中rabbit 应用程序的配置参数cluster_partition_handling 设置为:

    • autoheal
    • pause_minority
    • pause_if_all_down

    如果使用pause_if_all_down模式,需要额外的参数:

    • nodes: 应该无法暂停的节点
    • recover:恢复动作,可以是ignoreautoheal

    ...

    选择哪种模式?

    重要的是要理解允许 RabbitMQ 自动处理网络分区需要权衡取舍。

    如介绍中所述,要通过通常不可靠的链路连接 RabbitMQ 集群,首选 Federation 或 Shovel。

    话虽如此,以下是一些指导方针,可帮助操作员确定哪种模式可能合适,也可能不合适:

    • ignore:当网络可靠性实际上可能最高且节点可用性最重要时使用。例如,所有集群节点可以在同一个机架或同等设备中,通过交换机连接,该交换机也是通往外部世界的路由。
    • pause_minority:适合在单个区域中跨机架或可用区进行集群时,一次丢失大部分节点(区域)的概率被认为非常低。这种模式牺牲了一些可用性,以便在丢失的节点恢复时自动恢复。
    • autoheal:适用于更关注服务连续性而非节点间数据一致性的情况。

    【讨论】:

    • 可靠在实践中如何工作autoheal 模式?双节点集群之间网络故障后是否会自动重新连接并相互同步?
    【解决方案3】:

    从这种故障中恢复的另一种方法是使用 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 主节点时发生)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-14
      • 2016-09-25
      相关资源
      最近更新 更多