集群和网络分区
简介
本指南涵盖了集群的一个特定方面:节点之间的网络故障、其影响和恢复选项。有关集群的概览,请参阅集群和对等发现和集群形成指南。
集群可用于实现不同的目标:通过复制提高数据安全性,提高客户端操作的可用性,提高整体吞吐量等等。不同的配置最适合不同的目的。
集群成员之间网络连接故障会影响数据一致性和客户端操作的可用性(如 CAP 定理)。由于不同的应用程序对一致性的要求不同,并且可以承受不同程度的不可用性,因此提供了不同的分区处理策略。
检测网络分区
如果一个节点无法在默认情况下为期 60 秒联系到另一个节点,则节点会确定其对等节点是否已关闭。如果两个节点恢复联系,并且都认为对方已关闭,则节点将确定已发生分区。这将以类似以下形式写入 RabbitMQ 日志
2020-05-18 06:55:37.324 [error] <0.341.0> Mnesia(rabbit@warp10): ** ERROR ** mnesia_event got {inconsistent_database, running_partitioned_network, rabbit@hostname2}
可以通过服务器日志、HTTP API(用于监控)和CLI 命令识别分区是否存在。
rabbitmq-diagnostics cluster_status
rabbitmq-diagnostics cluster_status
通常会显示分区的空列表。
rabbitmq-diagnostics cluster_status
# => Cluster status of node rabbit@warp10 ...
# => Basics
# =>
# => Cluster name: local.1
# =>
# => ...edited out for brevity...
# =>
# => Network Partitions
# =>
# => (none)
# =>
# => ...edited out for brevity...
但是,如果发生网络分区,则有关分区的的信息将显示在那里。
rabbitmqctl cluster_status
# => Cluster status of node rabbit@warp10 ...
# => Basics
# =>
# => Cluster name: local.1
# =>
# => ...edited out for brevity...
# =>
# => Network Partitions
# =>
# => Node flopsy@warp10 cannot communicate with hare@warp10
# => Node rabbit@warp10 cannot communicate with hare@warp10
HTTP API 将在 GET /api/nodes
端点中的 partitions
下为每个节点返回分区信息。
如果发生分区,管理 UI 将在概述页面上显示警告。
网络分区期间的行为
在网络分区存在期间,集群的两侧(或更多侧)可以独立发展,双方都认为对方已崩溃。这种情况称为脑裂。队列、绑定、交换机可以分别创建或删除。
仲裁队列将在多数侧选举一个新的领导者。少数侧的仲裁队列副本将不再进行(即接受新消息、传递给消费者等),所有这些工作都将由新的领导者完成。
除非配置使用分区处理策略(例如 pause_minority
),否则即使在网络连接恢复后,拆分也将继续。
由挂起和恢复引起的分区
虽然我们指的是“网络”分区,但实际上分区是指集群的不同节点在没有任何节点发生故障的情况下通信中断的任何情况。除了网络故障外,对正在运行的集群节点使用整个操作系统的挂起和恢复也会导致分区 - 因为挂起的节点不会认为自己发生了故障,甚至停止,但集群中的其他节点会认为它已这样做了。
虽然可以通过在笔记本电脑上运行并关闭盖子来挂起集群节点,但发生这种情况的最常见原因是虚拟机已被虚拟机管理程序挂起。
虽然在虚拟化环境或容器中运行 RabbitMQ 集群是可以的,但**请确保在运行时不要挂起 VM**。
请注意,某些虚拟化功能(例如将 VM 从一个主机迁移到另一个主机)往往会涉及挂起 VM。
由挂起和恢复引起的分区往往是不对称的 - 挂起的节点不一定将其他节点视为已关闭,但会被集群的其余部分视为已关闭。这对pause_minority模式具有特殊意义。
从脑裂中恢复
要从脑裂中恢复,首先选择一个您最信任的分区。此分区将成为要使用的系统状态(模式、消息)的权威;其他分区上发生的任何更改都将丢失。
停止其他分区中的所有节点,然后重新启动它们。当它们重新加入集群时,它们将从受信任的分区恢复状态。
最后,您还应该重新启动受信任分区中的所有节点以清除警告。
停止整个集群并重新启动它可能更简单;如果是这样,请确保您启动的**第一个**节点来自受信任的分区。
分区处理策略
RabbitMQ 还提供三种自动处理网络分区的方法:pause-minority
模式、pause-if-all-down
模式和 autoheal
模式。默认行为称为 ignore
模式。
在 pause-minority 模式下,RabbitMQ 会自动暂停确定自己处于少数(即节点总数的一半或少于一半)的集群节点,并在看到其他节点关闭后。因此,它选择分区容错而不是 CAP 定理中的可用性。这确保在发生网络分区的情况下,最多只有一个分区中的节点将继续运行。少数节点将在分区开始时暂停,并在分区结束时重新启动。此配置可以防止脑裂,因此能够自动从网络分区中恢复而不会出现不一致。
在 pause-if-all-down 模式下,RabbitMQ 将自动暂停无法访问任何列出节点的集群节点。换句话说,所有列出的节点都必须关闭,RabbitMQ 才能暂停集群节点。这类似于 pause-minority 模式,但是,它允许管理员决定首选哪些节点,而不是依赖于上下文。例如,如果集群由机架 A 中的两个节点和机架 B 中的两个节点组成,并且机架之间的链接断开,则 pause-minority 模式将暂停所有节点。在 pause-if-all-down 模式下,如果管理员列出了机架 A 中的两个节点,则只有机架 B 中的节点将暂停。请注意,列出的节点可能会被拆分到分区的两侧:在这种情况下,没有任何节点会暂停。这就是为什么存在一个额外的忽略/自动修复参数来指示如何从分区中恢复。
在 autoheal 模式下,如果认为发生了分区,RabbitMQ 将自动决定获胜分区,并将重新启动不在获胜分区中的所有节点。与 pause_minority 模式不同,它在分区结束时生效,而不是在分区开始时生效。
获胜分区是连接了最多客户端的分区(或者如果这导致平局,则连接了最多节点的分区;如果这仍然导致平局,则以未指定的方式选择其中一个分区)。
您可以通过为配置文件中的 rabbit
应用程序设置配置参数 cluster_partition_handling
来启用任一模式,如下所示:
autoheal
pause_minority
pause_if_all_down
如果使用 pause_if_all_down
模式,则需要其他参数。
nodes
:应该不可用以暂停的节点。recover
:恢复操作,可以是ignore
或autoheal
。
使用 pause_if_all_down
的示例配置代码段
cluster_partition_handling = pause_if_all_down
## Recovery strategy. Can be either 'autoheal' or 'ignore'
cluster_partition_handling.pause_if_all_down.recover = ignore
## Node names to check
cluster_partition_handling.pause_if_all_down.nodes.1 = rabbit@myhost1
cluster_partition_handling.pause_if_all_down.nodes.2 = rabbit@myhost2
选择哪种模式?
重要的是要了解,允许 RabbitMQ 自动处理网络分区会带来权衡。
如引言中所述,要通过通常不可靠的链接连接 RabbitMQ 集群,请首选联合或铲运机。
话虽如此,以下是一些指南,可帮助操作员确定哪种模式可能合适或不合适。
ignore
:当网络可靠性在实践上尽可能高且节点可用性至关重要时使用。例如,所有集群节点都可以在同一个机架或等效位置,通过交换机连接,并且该交换机也是通往外部世界的路由。pause_minority
:当跨机架或单个区域中的可用区进行集群,并且一次丢失大多数节点(区域)的可能性被认为非常低时适用。此模式牺牲了一些可用性,以换取在丢失的节点恢复时自动恢复的功能。autoheal
:当更关注服务连续性而不是跨节点的数据一致性时适用。
关于 Pause-minority 模式的更多信息
已暂停节点上的 Erlang VM 将继续运行,但节点不会在任何端口上侦听或以其他方式可用。它们将每秒检查一次以查看集群的其余部分是否已重新出现,如果已重新出现,则重新启动。
请注意,即使节点当时处于少数,它们也不会在启动时进入暂停状态。预计启动时出现的任何此类少数情况都是由于集群的其余部分尚未启动。
另请注意,RabbitMQ 将暂停集群中不属于**严格**多数的节点 - 即包含超过一半节点的节点。因此,在两个节点的集群上启用 pause-minority 模式不是一个好主意,因为在任何网络分区**或节点故障**的情况下,两个节点都将暂停。但是,关于完整性,pause_minority
模式比 ignore
模式更安全。对于超过两个节点的集群,特别是如果最可能的网络分区形式是单个少数节点脱离网络,则可用性与 ignore
模式一样好。
请注意,pause_minority
模式不会采取任何措施来防御由集群节点暂停导致的分区。这是因为已暂停的节点永远不会看到集群的其余部分消失,因此不会有任何触发器将其自身与集群断开连接。