网络分区(network partitions)
网络设备故障导致的网络分裂。比如,存在A\B\C\D\E五个节点,A\B处于同一子网,B\C\D处于另外一子网,中间通过交换机相连。若两个子网间的交换机故障了即发生了网络分区,A\B和C\D\E便不能通讯。
某些系统是partition-tolerant的,也即,即使发生了网络分区系统分裂为了多个子系统,整个系统仍能正常工作。
RabbitMQ cluster不能很好地处理Network Partition。RabbitMQ将queue、exchange、bindings等信息存储在Erlang的分布式数据库Mnesia中。所以出现Network partition时RabbitMQ的众多行为与Mnesia的行为密切相关。
Network Partition的判定
若某一node在一段时间内(取决于net_ticktime的设置)不能与另一node取得联系,则Mnesia认为未能与之取得联系的node宕掉了。若两个node彼此恢复联系了,但都曾以为对方宕掉了,则Manesia断定发生过Network partition。
发生Network Partition后RabbitMQ的行为
若发生了network partition,cluster中的双方(或多方)将独立存在,每一方都将认为其他方已经崩溃了。Queues、bindings、exchanges可以各自独立的创建、删除。对于Mirrored queues,处于不同network partition的每一方都会拥有各自的master,且各自独立的读写。(也可能发生其他诡异的行为)。若network partition恢复了,cluster的状态并不能自动恢复到network partition发生前的状态,直至采取措施进行修复。
网络分区的可能原因
只要cluster中的不同node自身没有失效但之间的通信发生了中断都可认为是发生了Partitions。比如,整个OS的挂起会导致其中的cluster nodes的挂起,但这些nodes却不认为自身失效或停止了,而cluster中的其它nodes不能与之取得联系,会认为这些nodes down掉了。举个例子:若cluster中的一个node运行在笔记本电脑上,合上电脑屏幕就有可能导致node挂起。另外,若cluster中的node运行在虚拟机中,则管理程序可能导致虚拟机挂起,从而使node挂起。
- 情况1:集群中的nodes,都没有故障下线,但是node之间通信中断;
- 情况2:暂停/恢复运行中node的操作系统也可能导致network分区:暂停的node不认为它已经fail或stop,但集群中的其他nodes认为它已经fail了。
- 情况3:发生这种情况的最常见原因是:虚拟机已被虚拟机管理程序挂起;
- 情况4:虚拟机的迁移(rabbitmq运行在该vm上),也可能会导致vm被挂起,从而发生网络分区
- 情况总结:就是某个node因各种原因,和集群中的其他节点发生通信中断,虽然该节点不认为自己下线,但是集群中的其他节点已经认为该节点下线了。
检查网络分区
可以通过rabbitmqctl cluster_status
来查看是否发生了网络分区
正常的状态信息:
[root@rmq-node3 ~]# rabbitmqctl cluster_status
Cluster status of node 'rabbit@rmq-node3'
[{nodes,[{disc,['rabbit@rmq-node2','rabbit@rmq-node1']},
{ram,['rabbit@rmq-node3']}]},
{running_nodes,['rabbit@rmq-node1','rabbit@rmq-node2','rabbit@rmq-node3']},
{cluster_name,<<"rabbit@rmq-node1">>},
{partitions,[]}, #注意,这里为空数组,表明没有发生网络分区
{alarms,[{'rabbit@rmq-node1',[]},
{'rabbit@rmq-node2',[]},
{'rabbit@rmq-node3',[]}]}]
发生网络分区的状态信息:
[root@rmq-node3 ~]# rabbitmqctl cluster_status
Cluster status of node 'rabbit@rmq-node3'
[{nodes,[{disc,['rabbit@rmq-node2','rabbit@rmq-node1']},
{ram,['rabbit@rmq-node3']}]},
{running_nodes,['rabbit@rmq-node1','rabbit@rmq-node2','rabbit@rmq-node3']},
{cluster_name,<<"rabbit@rmq-node1">>},
{partitions,[{'rabbit@rmq-node1',['rabbit@rmq-node2','rabbit@rmq-node3']}]}, #这里是发生了network partitions
{alarms,[{'rabbit@rmq-node1',[]},
{'rabbit@rmq-node2',[]},
{'rabbit@rmq-node3',[]}]}]
当发生网络分区时,会提示如下信息:
While running in this partitioned state, changes (such as queue or exchange declaration and binding) which take place in one partition will not be visible to other partition(s). Other behaviour is not guaranteed.
==>表明 元数据的改变,不会在节点之间同步
也可以通过查看日志找到该问题:
vi /var/log/rabbitmq/rabbit-xxx.log
=ERROR REPORT==== 9-Aug-2018::20:15:45 ===
Mnesia('rabbit@rmq-node2'): ** ERROR ** mnesia_event got {inconsistent_database, starting_partitioned_network, 'rabbit@rmq-node1'}
网络分区的恢复
首先选一个最信任的partition,Mnesia使用该partition中的状态,其他partitions中发生的变化都将丢失。
停止其他partitions中的所有nodes,之后重启这些nodes。当这些nodes重新加入cluster后将从信任的partition恢复状态。
最后还需重启信任的partition中的所有nodes以清除network partition的警告信息
Rabbitmq自动处理网络分区的3种模式
RabbitMQ提供了3种自动处理network partitions的方式:默认为ignore模式,也即需要手工处理
- pause-minority mode:暂停少数模式;
- pause-if-all-down mode:暂停-如果全部停止模式
- autoheal mode:自动愈合模式
pause-minority mode:暂停少数模式
在pause-minority模式下,察觉其他nodes down掉后,RabbitMQ将自动暂停认为自己是少数派的 nodes(例如小于或等于总nodes数的一半),network partition一旦发生,“少数派”的nodes将立刻暂停,直至partition结束后重新恢复。这可以保证在network partition发生时,至多只有一个partition中的nodes继续运行。(牺牲可用性保证一致性)
若所有分区的nodes个数都小于总nodes个数一半,则意味着所有分区的nodes都会认为自己是少数派,即所有nodes都将暂停;
pause-if-all-down mode:暂停-如果全部停止模式
http://www.rabbitmq.com/partitions.html
autoheal模式
在autoheal模式下一旦发生了partition,RabbitMQ将自动确定一个优胜partition,然后重启所有不在优胜partition中的nodes。
获胜的partition为拥有最多客户端连接的partition(若连接相同则为节点最多的partition)。
关于自动处理partitions的设置在配置文件的cluster_partition_handling参数中进行。
各自的适用场景
network partitions自动处理并不能保证cluster不出任何问题。
一般来说可作如下选择:
- ignore:若网络非常可靠。所有nodes在同一机架,通过交换机连接,该交换机也是通往外部网络的出口。在cluster的某一部分故障时不希望其余部分受影响。或者cluster只有两个node。
- pause_minority:网络较不可靠。cluster处于EC2的3个AZ中,假定每次至多只有其中一个AZ故障,想要剩余的AZ继续提供服务而故障的AZ中的nodes在AZ恢复后重新自动加入到cluster。
- autoheal:网络很不可靠。与数据完整性相比更关注服务的持续性。cluster只有两个node。
关于pause-minority模式
暂停的nodes上Erlang VM将继续运行但不监听任何端口或者做其他工作。它们将每秒检测一次cluster中的其他nodes是否可见,若可见则从pause状态唤醒。
注意:
nodes在启动时不会进入paused状态,即使是处于“少数派”;
RabbitMQ可能会暂停非严格意义上的“少数派”中的nodes。如,包含多于总nodes总数一半的nodes。因此在只包含两个nodes的cluster中使用pause-minority模式并非好主意,因为在network partition发生或者node失败时有可能两个node都会暂停。然而,在包含两个以上nodes的cluster中pause_minority模式要比ignore更安全;
对于因cluster nodes 挂起引起的partitions pause_minority模式无能为力。因为挂起的node将不能看到剩余node是否恢复“可见”,因而不能触发从cluster中断开。