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 已經宕機,於是會出現:
- 如果 A 擁有 b 數據的備份,則 A 將以完整數據運行,B 也同樣以完整數據運行,這將很可能導致兩個節點同時讀寫共享數據造成數據損壞
- 如果 A、B 各自僅擁有 a、b 數據,那么兩個節點要么均無法啟動,要么以瓜分完整共享數據的方式啟動
總之,無論是哪一種,都不是我們希望見到的
因此,在 RabbitMQ 官方文檔中,明確建議了,不要在廣域網環境下使用,否則,應該使用 federation 或者 shovel 插件
腦裂問題的解決
當然,我們不能要求集群的可用性或網絡的健康達到 100%,即使在局域網中,發生故障的可能性也是存在的
RabbitMQ 3.1 以上版本提供了配置來解決這個問題:
[ {rabbit, [{tcp_listeners,[5672]}, {cluster_partition_handling, ignore}] } ]
RabbitMQ 提供了三種配置:
- ignore:默認配置,發生網絡分區時不作處理,當認為網絡是可靠時選用該配置
- autoheal:各分區協商后重啟客戶端連接最少的分區節點,恢復集群(CAP 中保證 AP,有狀態丟失)
- pause_minority:分區發生后判斷自己所在分區內節點是否超過集群總節點數一半,如果沒有超過則暫停這些節點(保證 CP,總節點數為奇數個)
使用 pause_minority 可以有效解決腦裂問題,但是會讓集群在出現問題后無法使用