Rabbitmq管理界面上也提示报错:
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.
rabbitmq 脑裂问题,实质上是个网络分区问题, 确切来说是网络不稳定导致的问题。
rabbitmq集群的网络分区容错性不好,在网络比较差的情况下容易出错,最明显的就是脑裂问题了。
不要将你的rabbitmq集群建立在广域网上,除非你使用federation或者shovel等插件。
判定条件
默认情况下,一个节点在60s之内不能连接上另一个节点(可用net_ticktime 参数调整),就判定这个节点挂了。即使之后节点网络又连通了,由于节点都认为对方挂了,所以Mnesia 还是会发送网络分区的情况并且将情况记录在日志中。(许多围绕网络分区的细节都与Mnesia的行为相关。Mnesia是一个分布式数据库管理系统(DBMS),适合于电信和其它需要持续运行和具备软实时特性的Erlang应用,是构建电信应用的控制系统平台开放式电信平台(OTP)的一部分。)
除了网络失败原因,操作系统的挂起和恢复也会导致集群内部节点发生分区, 因为发生挂起的节点不会认为自己已经失败或者不能工作,但是其他节点会这么认为。比如:将节点运行在你的电脑上,你合上电脑;或者你将节点运行在虚拟机里,系统管理程序将节点挂起了。
模拟脑裂故障:
- 在其中一台服务器上封禁默认的内部通信端口25672:
iptables -A INPUT -p tcp --dport 25672 -j DROP iptables -A OUTPUT -p tcp --dport 25672 -j DROP
- 观察两台服务器的日志,会有如下输出:
- 节点1
- 节点2
此时只判定出net_tick_timeout,要等网络恢复之后,即解封25672端口之后才会判定出现网络分区。
- 解封25672端口:
iptables -D INPUT 1 iptables -D OUTPUT 1
- 两个节点的日志都会提示发生了脑裂:
2021-04-13 01:55:35.219 [error] <0.6318.0> Mnesia(rabbit@pc2): ** ERROR ** mnesia_event got {inconsistent_database, running_partitioned_network, rabbit@pc1}
原因
由于网络问题导致集群出现了脑裂。
正常情况下,通过rabbitmqctl cluster_status命令查看到的信息中partitions那一项是空的,就像这样:
# rabbitmqctl cluster_status Cluster status of node rabbit@smacmullen ... [{nodes,[{disc,[hare@smacmullen,rabbit@smacmullen]}]}, {running_nodes,[rabbit@smacmullen,hare@smacmullen]}, {partitions,[]}] ...done.
然而当网络分区发生时,会变成这样:
# rabbitmqctl cluster_status Cluster status of node rabbit@smacmullen ... [{nodes,[{disc,[hare@smacmullen,rabbit@smacmullen]}]}, {running_nodes,[rabbit@smacmullen,hare@smacmullen]}, {partitions,[{rabbit@smacmullen,[hare@smacmullen]}, {hare@smacmullen,[rabbit@smacmullen]}]}] ...done.
临时手动处理
- 在出现问题的节点上执行: rabbitmqctl stop_app
- 在出现问题的节点上执行: rabbitmqctl start_app
注意:mq集群不能采用kill -9 杀死进程,否则生产者和消费者不能及时识别mq的断连,会影响生产者和消费者正常的业务处理。
配置脑裂后自动修复
- 修改节点的配置文件
在/etc/rabbitmq下新建rabbitmq.conf,加入
[ {rabbit, [{tcp_listeners,[5672]}, {cluster_partition_handling, autoheal} ]} ]
- 若已有配置文件,则直接添加{cluster_partition_handling, autoheal}配置,示例:
vi /etc/rabbitmq/rabbitmq.config - 重启rabbitmq
systemctl restart rabbitmq-server
再次模拟脑裂,发现会通过重启其中一个节点自动恢复此问题:
网络分区处理策略
rabbitmq 提供了3种模式
- ignore 默认配置,即分区不做任何处理。要使用这种,就要保证网络高可用,例如,节点都在一个机架上,用的同一个交换机,这个交换机连上一个WAN,保证网络稳定。
- pause_minority。优先暂停‘少数派’。就是节点判断自己在不在‘少数派’(少于或者等于集群中一半的节点数),在就自动关闭,保证稳定区的大部分节点可以继续运行。
- autoheal, 关闭客户端连接数最多的节点。 这里比较有意思,rabbitmq 会自动挑选一个‘获胜’分区,即连接数最小的,重启其他分区。(如果平手,就选节点多的,如果节点也一致,那就以未知方式挑选‘获胜者’)。这个更关心服务的连续性而不是数据的完整性。