【问题描述】
在OpenStack云平台有3个控制节点,同时也部署了3个Rabbitmq服务构成1个消息中间件集群,当集群运行一段时间后,巡检时发现Rabbitmq集群出现脑裂现象
执行一下指令,检查Rabbitmq集群是否出现脑裂:
rabbitmqctl cluster_status
如果返回信息中 partitions 那一项是空的,如下这样,说明集群未出现脑裂
[{nodes,[{disc,['rabbit@node1', 'rabbit@node2','rabbit@node3']}]},
{running_nodes,['rabbit@node2','rabbit@node1','rabbit@node3']},
{cluster_name,<<"rabbit@node1">>},
{partitions,[]}]
如果返回信息中 partitions 那一项不是空的,如下这样,说明集群出现脑裂
[{nodes,[{disc, ['rabbit@node1','rabbit@node2','rabbit@node3']}]},
{running_nodes,['rabbit@node1']},
{cluster_name,<<"rabbit@node1">>},
{partitions,[{'rabbit@node1'['rabbit@node2','rabbit@node3']}]}]
【引发脑裂】
当1个集群中网络分区不可能完全避免,网络设备(比如中继设备、网卡)出现故障也会导致网络分区。当出现网络分区时,不同分区里的节点会认为不属于自身所在分区的节点都已经挂了,对 queue、exchange、binding 的操作仅对当前分区有效。在 RabbitMQ 的默认配置下,即使网络恢复了也不会自动处理网络分区带来的问题从而恢复集群。RabbitMQ(3.1+)会自动探测网络分区,并且提供了配置来解决这个问题
[
{rabbit,
[{tcp_listeners,[5672]},
{cluster_partition_handling, ignore}]
}
].
ignore:默认配置,发生网络分区时不作处理,当认为网络是可靠时选用该配置。当网络分区的时候,RabbitMQ不会自动做任何处理,即需要手动处理
autoheal:各分区协商后重启客户端连接最少的分区节点,恢复集群(CAP 中保证 AP,有状态丢失)
pause_if_all_down
pause_minority:分区发生后判断自己所在分区内节点是否超过集群总节点数一半,如果没有超过则暂停这些节点(保证 CP,总节点数为奇数个)。当发生网络分区时,集群中的节点在观察到某些节点down掉时,会自动检测其自身是否处于少数派(小于或者等于集群中一般的节点数)。少数派中的节点在分区发生时会自动关闭,当分区结束时又会启动。这里的关闭是指RabbitMQ application关闭,而Erlang VM并不关闭,这个类似于执行了rabbitmqctl stop_app命令。处于关闭的节点会每秒检测一次是否可连通到剩余集群中,如果可以则启动自身的应用,相当于执行rabbitmqctl start_app命令
需要注意的是RabbitMQ也会关闭不是严格意义上的大多数。比如在一个集群中只有两个节点的时候并不适合采用pause-minority模式,因为由于其中任何一个节点失败而发生网络分区时,两个节点都会被关闭。当网络恢复时,有可能两个节点会自动启动恢复网络分区,也有可能还是保持关闭状态。然而如果集群中的节点远大于两个时,pause_minority模式比ignore模式更加的可靠,特别是网络分区通常是由于单个节点网络故障而脱离原有分区引起的。不过也需要考虑2v2, 3v3这种情况,可能会引起所有集群节点的关闭。这种处理方式适合集群节点数大于2个且最好为奇数的情况
【脑裂影响】
当Rabbitmq消息中间件出现脑裂时,会影响集群内部的消息通讯效率,会出现消息的积压,不断影响整个集群,若是脑裂情况进一步恶化,导致更多的Rabbitmq无法正常处理消息,又会引发进一步的云平台服务异常,所以应该尽早处理
【解决脑裂】
1)方法一
首先选择一个最信任的分区(master多的节点)。这个分区将有系统状态(模式、消息)使用的权限;其他分区上发生的任何更改都将丢失
停止其他分区中的所有节点,然后重新启动。这些节点重新加入集群时,将从受信任的分区恢复状态
重新启动受信任分区中的所有节点以清除警告
例如:{partitions,[{'rabbit@node1'['rabbit@node2','rabbit@node3']}]}]中最信任的分区 ['rabbit@node2','rabbit@node3'] ,重新启动并检查 rabbit@node1 上的 Rabbitmq 服务,启动指令如下:
systemctl restart rabbitmq
systemctl status rabbitmq
此时,检查Rabbitmq集群状态,已经恢复正常,脑裂现象消失
2)方法二
停止整个集群并重新启动,但是确保启动的第一个节点来自受信任的分区
rabbitmq集群不能采用kill -9 杀死进程,否则生产者和消费者不能及时识别mq的断连,会影响生产者和消费者正常的业务处理
【后续检查】
1、Rabbitmq集群是否有消息积压,是否对应的消息队列通讯正常,登录到对应的WebUI界面
http://IP:15672/
若是发现界面上处理消息为 0 ,一直没有起色,则依次将 node2 和 node3 上的 Rabbitmq 服务启动,然后再检查 Rabbitmq集群状态,以及页面消息处理状况是否稳定
2、检查OpenStack云平台是否可以正常提供服务,是否可以正常创建 CVM ,CVM 通讯是否正常(ping 检查,是否能ping 通CVM)
若是无法正常创建 CVM ,此时需要依次启动 OpenStack 控制节点上的 Neutron(网络)服务和 Nova(计算)服务,执行一下指令:
先查出有哪些 Neutron 和 Nova 服务,查出对应的服务之后,依次启动并检查服务启动状态
systemctl | grep neutron
systemctl restart neutron
systemctl status neutron
......
systemctl | grep nova
systemctl restart nova
systemctl status nova
......
systemctl | grep ovs
systemctl restart ovs
systemctl status ovs
......
重启完服务之后,OpenStack 云平台可以正常创建 CVM 了
【参考资料】
Rabbitmq官网:
https://www.rabbitmq.com/partitions.html
网络分区:
https://en.wikipedia.org/wiki/Network_partition
脑裂问题:
https://en.wikipedia.org/wiki/Split-brain_%28computing%29
详情请见,微信公众号
写在最后:
真正的朋友应该是虽然很久才能见一次,但每次见面既不会感到时光让我们缺失了共同语言,也不需耗费精力去解释彼此不在时发生的那些事的前因后果,就好像昨天才刚刚一起喝茶聊天过一样