記一次RabbitMQ的腦裂(網絡分區)問題
1、問題描述
Mnesia reports that this RabbitMQ cluster has experienced a network partition. There is a risk of losing data

一、什么是MQ腦裂?
-
網絡分區
如果另一個節點在一段時間內(默認為 60 秒)無法與其聯系,則節點會確定其對等方是否關閉。如果兩個節點重新接觸,並且都認為另一個節點已關閉,則節點將確定發生了分區。
當網絡分區就位時,集群的兩個(或更多!)方可以獨立發展,雙方都認為對方已經崩潰。這種情況被稱為裂腦。隊列、綁定、交換可以單獨創建或刪除。
-
除非將分區處理策略(例如pause_minority)配置為使用,否則即使在網絡連接恢復后,拆分仍將繼續
二、 什么原因造成腦裂,怎樣查看?
這是由於網絡問題導致集群出現了腦裂。
正常情況下,通過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.
三、怎么解決MQ腦裂?
原因是rabbitmq集群在配置時未設置出現網絡分區處理策略,先要將集群恢復正常,再設置出現網絡分區處理策略,步驟如下:
- (1)首先需要挑選一個信任的分區,這個分區才有決定Mnesia內容的權限,發生在其他分區的改變將不被記錄到Mnesia中而直接丟棄。
- (2)停止(stop)其他分區的節點,然后啟動(start)這些節點,之后重新將這些節點加入到當前信任的分區之中。
rabbitmqctl stop_app
rabbitmqctl start_app
- (3)最后,你應該重啟(restart)信任的分區中所有的節點,以去除告警。你也可以簡單的關閉整個集群的節點,然后再啟動每一個節點,當然,你要確保你啟動的第一個節點在你所信任的分區之中。
注意:mq集群不能采用kill -9 殺死進程,否則生產者和消費者不能及時識別mq的斷連,會影響生產者和消費者正常的業務處理
- (4)設置出現網絡分區處理策略,這里設置為autoheal,下面會詳細說明其它策略
在/etc/rabbitmq下新建rabbitmq.conf,加入:
[ {rabbit, [{tcp_listeners,[5672]}, {cluster_partition_handling, autoheal} ]} ].
網絡分區處理策略:
有以下3種處理策略:
- (1)ignore
默認類型,不處理。
要求你所在的網絡環境非常可靠。例如,你的所有 node 都在同一個機架上,通過交換機互聯,並且該交換機還是與外界通信的必經之路。
- (2)pause_minority
rabbitmq節點感知集群中其他節點down掉時,會判斷自己在集群中處於多數派還是少數派,也就是判斷與自己形成集群的節點個數在整個集群中的比例是否超過一半。如果是多數派,則正常工作,如果是少數派,則會停止rabbit應用並不斷檢測直到自己成為多數派的一員后再次啟動rabbit應用。
注意:這種處理方式集群通常由奇數個節點組成。在CAP中,優先保證了CP。
注意:pause_minority適用情形有限制,如3個節點集群,每次只down1個時,此模式適用。但如果網絡都出問題,3節點會獨立形成3個集群。
- (3)autoheal
你的網絡環境可能是不可靠的。你會更加關心服務的可持續性,而非數據完整性。你可以構建一個包含2個node的集群。
當網絡分區恢復后,rabbitmq各分區彼此進行協商,分區中客戶端連接數最多的為勝者,其余的全部會進行重啟,恢復到同步狀態