集群与网络分区
简介
本指南涵盖了集群的一个特定方面:节点间的网络故障、其影响以及恢复选项。有关集群的概述,请参阅 集群 和 对等发现和集群形成 指南。
集群可用于实现不同的目标:通过复制提高数据安全性、提高客户端操作的可用性、提高整体吞吐量等。不同的配置最适合不同的目的。
集群成员之间的网络连接故障会影响数据一致性和可用性(根据 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 集群是可以的,但请**确保虚拟机在运行时不要被挂起**。
请注意,某些虚拟化功能(如虚拟机从一个主机迁移到另一个主机)通常涉及虚拟机被挂起。
由挂起和恢复引起的分区倾向于不对称——被挂起的节点不一定会认为其他节点已宕机,但会被集群其余部分视为宕机。这对 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 中的节点会暂停。请注意,列出的节点可能会跨越分区的两边:在这种情况下,没有节点会暂停。这就是为什么还有一个额外的 ignore/autoheal 参数来指示如何从分区中恢复。
在 autoheal 模式下,如果分区被视为发生,RabbitMQ 将自动确定一个获胜的分区,并重新启动不在获胜分区中的所有节点。与 pause_minority 模式不同,它在分区结束时生效,而不是在分区开始时生效。
获胜分区是连接的客户端数量最多的分区(如果客户端数量相同,则拥有节点数最多的分区;如果节点数量也相同,则以不确定的方式选择一个分区)。
您可以通过在 配置文件 中为 rabbit 应用程序设置 cluster_partition_handling 配置参数来启用任一模式,参数值为:
autohealpause_minoritypause_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 集群,请首选 Federation 或 Shovel。
话虽如此,以下是一些指南,可以帮助操作员确定哪种模式可能适用或不适用:
ignore:当网络可靠性尽可能高且节点可用性最重要时使用。例如,所有集群节点都可以位于同一机架或等效位置,通过交换机连接,并且该交换机也是通往外界的路由。pause_minority:适用于跨机架或区域(availability zones)在一个区域内进行集群,并且一次丢失大多数节点(区域)的概率被认为非常低。此模式以牺牲部分可用性为代价,以在丢失的节点恢复时实现自动恢复。autoheal:适用于比跨节点数据一致性更关心服务连续性的情况。
更多关于 pause-minority 模式
暂停节点上的 Erlang VM 将继续运行,但节点不会监听任何端口,也不会有其他可用性。它们将每秒检查一次,以查看集群的其余部分是否已重新出现,并在出现时启动。
请注意,节点在启动时不会进入暂停状态,即使它们当时处于少数。预计任何此类启动时的少数情况是由于集群的其余部分尚未启动。
另请注意,RabbitMQ 将暂停不构成集群**严格多数**(即包含超过一半节点)的节点。因此,在两个节点的集群上启用 pause-minority 模式是不明智的,因为在发生任何网络分区**或节点故障**时,两个节点都会暂停。但是,与 ignore 模式相比,pause_minority 模式在完整性方面更安全。对于超过两个节点的集群,特别是当最可能发生网络分区形式是单个少数节点掉线时,可用性与 ignore 模式一样好。
请注意,pause_minority 模式对由集群节点被 挂起 引起的分区没有任何防御作用。这是因为被挂起的节点永远不会看到集群的其余部分消失,因此没有触发器来断开与集群的连接。