代码改变世界

解决RabbitMQ镜像集群脑裂问题

2021-06-22 16:45  天心PHP  阅读(1997)  评论(0编辑  收藏  举报

1、现象:

项目中使用了rabbitmq的镜像模式集群,两个节点,昨天出现MQ集群不能正常消息通信,打开web管理界面:

 

 

 

Network partition detected
Mnesia reports that this RabbitMQ cluster has experienced a network partition. There is a risk of losing data. Please read RabbitMQ documentation about network partitions and the possible solutions.

原来是集群出现脑裂现象,网络分区中一个节点在一分钟(或者一个net_ticktime时间)内不能连接上另一个节点,那么Mnesia会认为另一个节点已经挂了。就算之后两个节点连通,但是这两个节点都认为对方已经挂了,Mnesia此时认定发生了网络分区的情况。rabbitmq出错日志如下:

=INFO REPORT==== 11-Jun-2019::19:11:57 ===
node 'rabbit@lg-mq01' up

=ERROR REPORT==== 11-Jun-2019::19:11:57 ===
Mnesia('rabbit@lg-mq02'): ** ERROR ** mnesia_event got {inconsistent_database, running_partitioned_network, 'rabbit@lg-mq01'}

=INFO REPORT==== 11-Jun-2019::19:12:09 ===
accepting AMQP connection <0.15728.1484> (10.200.66.115:56670 -> 10.200.66.115:5672)

=INFO REPORT==== 11-Jun-2019::19:12:09 ===
connection <0.15728.1484> (10.200.66.115:56670 -> 10.200.66.115:5672): user 'xxxxx' authenticated and granted access to vhost 'leboGame'

=INFO REPORT==== 11-Jun-2019::19:12:14 ===
accepting AMQP connection <0.22202.1484> (10.200.66.115:56686 -> 10.200.66.115:5672)

=INFO REPORT==== 11-Jun-2019::19:12:14 ===
connection <0.22202.1484> (10.200.66.115:56686 -> 10.200.66.115:5672): user 'xxxxx' authenticated and granted access to vhost 'leboGame'

=WARNING REPORT==== 11-Jun-2019::19:12:17 ===
closing AMQP connection <0.15728.1484> (10.200.66.115:56670 -> 10.200.66.115:5672):
client unexpectedly closed TCP connection

=INFO REPORT==== 11-Jun-2019::19:12:18 ===
accepting AMQP connection <0.20778.1484> (10.200.66.115:56700 -> 10.200.66.115:5672)

=INFO REPORT==== 11-Jun-2019::19:12:18 ===
connection <0.20778.1484> (10.200.66.115:56700 -> 10.200.66.115:5672): user 'xxxxx' authenticated and granted access to vhost 'leboGame'

=INFO REPORT==== 11-Jun-2019::19:54:58 ===
accepting AMQP connection <0.23143.1484> (10.200.66.115:61598 -> 10.200.66.115:5672)

2、解决办法:
原因是rabbitmq集群在配置时未设置出现网络分区处理策略,先要将集群恢复正常,再设置出现网络分区处理策略,步骤如下:
(1)首先需要挑选一个信任的分区,这个分区才有决定Mnesia内容的权限,发生在其他分区的改变将不被记录到Mnesia中而直接丢弃。
(2)停止(stop)其他分区的节点,然后启动(start)这些节点,之后重新将这些节点加入到当前信任的分区之中。

rabbitmqctl stop_app
rabbitmqctl start_app

(3)最后,你应该重启(restart)信任的分区中所有的节点,以去除告警。
你也可以简单的关闭整个集群的节点,然后再启动每一个节点,当然,你要确保你启动的第一个节点在你所信任的分区之中。
(4)设置出现网络分区处理策略,这里设置为autoheal,下面会详细说明其它策略
在/etc/rabbitmq下新建rabbitmq.conf,加入:

[
 {rabbit,
  [{tcp_listeners,[5672]},
   {cluster_partition_handling, autoheal}
]}
].

3、网络分区处理策略:
有以下3种处理策略:
(1)ignore
默认类型,不处理。
要求你所在的网络环境非常可靠。例如,你的所有 node 都在同一个机架上,通过交换机互联,并且该交换机还是与外界通信的必经之路。
(2)pause_minority
rabbitmq节点感知集群中其他节点down掉时,会判断自己在集群中处于多数派还是少数派,也就是判断与自己形成集群的节点个数在整个集群中的比例是否超过一半。如果是多数派,则正常工作,如果是少数派,则会停止rabbit应用并不断检测直到自己成为多数派的一员后再次启动rabbit应用。注意:这种处理方式集群通常由奇数个节点组成。在CAP中,优先保证了CP。
注意:pause_minority适用情形有限制,如3个节点集群,每次只down1个时,此模式适用。但如果网络都出问题,3节点会独立形成3个集群。
(3)autoheal
你的网络环境可能是不可靠的。你会更加关心服务的可持续性,而非数据完整性。你可以构建一个包含2个node的集群。
当网络分区恢复后,rabbitmq各分区彼此进行协商,分区中客户端连接数最多的为胜者,其余的全部会进行重启,恢复到同步状态。

 

文章二

 

所谓的脑裂问题,就是在多机热备的高可用 HA 系统中,当两个节点心跳突然断开,就分裂为了两个独立的个体,由于互相失去联系,都认为对方出现了故障,因此都会去争抢对方的资源,争抢启动,由此就会发生严重的后果

举个形象的例子,A 和 B 作为一个双机热备集群的两个节点,各自持有集群的一部分数据 -- a 和 b,这时,两机器之间突然无法通信,A 认为 B 已经挂掉,B 认为 A 已经宕机,于是会出现:

  1. 如果 A 拥有 b 数据的备份,则 A 将以完整数据运行,B 也同样以完整数据运行,这将很可能导致两个节点同时读写共享数据造成数据损坏
  2. 如果 A、B 各自仅拥有 a、b 数据,那么两个节点要么均无法启动,要么以瓜分完整共享数据的方式启动

总之,无论是哪一种,都不是我们希望见到的

因此,在 RabbitMQ 官方文档中,明确建议了,不要在广域网环境下使用,否则,应该使用 federation 或者 shovel 插件

脑裂问题的解决

当然,我们不能要求集群的可用性或网络的健康达到 100%,即使在局域网中,发生故障的可能性也是存在的

RabbitMQ 3.1 以上版本提供了配置来解决这个问题:

[
 
{rabbit,
 
[{tcp_listeners,[5672]},
 
{cluster_partition_handling, ignore}]
 
}
 
]

RabbitMQ 提供了三种配置:

  1. ignore:默认配置,发生网络分区时不作处理,当认为网络是可靠时选用该配置
  2. autoheal:各分区协商后重启客户端连接最少的分区节点,恢复集群(CAP 中保证 AP,有状态丢失)
  3. pause_minority:分区发生后判断自己所在分区内节点是否超过集群总节点数一半,如果没有超过则暂停这些节点(保证 CP,总节点数为奇数个)

使用 pause_minority 可以有效解决脑裂问题,但是会让集群在出现问题后无法使用