2011-12-28 78 views
10

之後沒有重新連接我的RabbitMQ簇在生產兩個節點和羣集與這些錯誤消息打破:RabbitMQ的集羣網絡故障

=錯誤報告==== 23日 - 12月2011 :: 4時21分34秒===
**節點兔@ rabbitmq02沒有響應**
**刪除(已逾時)連接**

= INFO REPORT ==== 23日 - 12月2011 :: 04 :21:35 ===
節點rabbit @ rabbitmq02丟失'rabbit'

=錯誤報告==== 2011年12月23日:: 04:21:49 ===
Mnesia(rabbit @ rabbitmq01):**錯誤** mnesia_event got {inconsistent_database,running_partitioned_network,rabbit @ rabbitmq02}

我試圖通過使用「tcpkill」殺死兩個節點之間的連接來模擬問題,羣集已斷開連接,並且令人驚訝的是兩個節點不嘗試重新連接!

當集羣中斷時,haproxy負載均衡器仍將兩個節點都標記爲活動狀態,並向兩者發送請求,儘管它們不在集羣中。

我的問題:

  1. 如果節點都配置爲集羣的工作,當我得到一個網絡故障,他們爲什麼不嘗試後重新連接?

  2. 如何識別損壞的集羣並關閉其中一個節點?與兩個節點分開工作時遇到一致性問題。

回答

8

從這種失敗中恢復的另一種方法是與Mnesia一起工作,Mnesia是RabbitMQ用作持久性機制的數據庫,RabbitMQ實例(以及主/從狀態)的同步由此控制。對於所有的詳情,請參閱以下網址:http://www.erlang.org/doc/apps/mnesia/Mnesia_chap7.html

這裏添加的相關章節:

有好幾次在Mnesia可以檢測網絡 已經由於通信故障分區。

一個是當Mnesia已經啓動並且Erlang節點再次獲得 聯繫。然後,Mnesia將嘗試聯繫Mnesia另一個 節點,以查看它是否也認爲網絡已被分割 一段時間。如果兩個節點上的Mnesia已經彼此記錄了mnesia_down條目 ,Mnesia會生成一個系統事件,稱爲 {inconsistent_database,running_partitioned_network,Node},該事件被髮送給Mnesia的事件處理程序和其他可能的訂閱者,其中 。 默認事件處理程序向錯誤記錄器報告錯誤。

Mnesia可能會檢測到由於通信故障而分割了網絡的另一種情況是啓動時。如果Mnesia 檢測到本地節點和另一個節點從彼此接收到mnesia_down ,則它生成{inconsistent_database, starting_partitioned_network,Node}系統事件並且如上所述的 那樣起作用。

如果應用程序檢測到已經存在通信故障 ,其可能造成不一致的數據庫,它可以使用 函數mnesia:set_master_nodes(製表,節點),從該 節點每個表可以被加載到精確定位。

在啓動時,無論mnesia中潛在的mnesia_down條目如何,Mnesia的正常表加載算法都將被繞過,並且將從表中定義的其中一個主節點加載該表。 節點可能只包含表中有複製副本的節點,並且如果節點爲空,則將重置特定表 的主節點恢復機制,並在下一個 重新啓動時使用正常加載機制。

函數mnesia:set_master_nodes(Nodes)爲所有 表設置主節點。對於每個表,它將確定其副本節點,並調用具有 包括在節點列表中的那些副本節點(即,TabNodes是該表的副本節點和 節點的交集)的mnesia:set_master_nodes(Tab,TabNodes)。如果交叉點爲空,則對特定表的主節點恢復機制將被重置,並且在下次重新啓動時將使用正常加載機制。

函數mnesia:system_info(master_node_tables)和 mnesia:table_info(Tab,master_nodes)可用於獲取有關潛在主節點的信息 。

確定通信失敗後要保留的數據是否在 Mnesia的範圍之外。一種方法是確定哪個「島」包含大部分節點。使用 關鍵表的{majority,true}選項可以確保不屬於「多數島」的部分 的節點不能更新這些表。請注意0​​這構成了少數節點服務的減少。這個 將是一個有利於更高一致性保證的折衷。

無論哪個表加載機制被激活,函數mnesia:force_load_table(Tab)都可以用來強制加載表 表。

這是從這樣的故障中恢復的一個更費時又複雜的方式..但會提供更好的粒度和通過數據控制應該是在最終的主節點可用的(這可以減少數據丟失的量可能發生在「合併」RabbitMQ大師時)。

9

RabbitMQ集羣在不可靠的網絡(RabbitMQ文檔的一部分)上無法正常工作。因此,當網絡故障發生時(在兩節點羣集中),每個節點都認爲它是羣集中的主節點和唯一節點。兩個主節點不會自動重新連接,因爲它們的狀態不會自動同步(即使是在RabbitMQ從站的情況下 - 實際的消息同步也不會發生 - 當從消息隊列中消耗消息時,從站只會「追上來」得到補充)。

要檢測是否有一個破碎簇,運行下面的命令:

rabbitmqctl cluster_status 

在每個形成該集羣的節點。如果集羣已損壞,則只能看到一個節點。喜歡的東西:

Cluster status of node [email protected] ... 
[{nodes,[{disc,[[email protected]]}]},{running_nodes,[[email protected]]}] 
...done. 

在這種情況下,你需要在所形成的原始簇的一部分(以便加入其他主節點(說rabbitmq1)的一個節點上運行以下命令集在羣集中作爲奴隸):

rabbitmqctl stop_app 

rabbitmqctl reset 

rabbitmqctl join_cluster [email protected] 

rabbitmqctl start_app 

最後再次檢查羣集狀態..這次你應該看到兩個節點。

注意:如果您在使用虛擬IP的HA配置中使用RabbitMQ節點(並且客戶端使用此虛擬IP連接到RabbitMQ),那麼應該成爲主節點的節點應該是具有虛擬IP。

+0

是否可以將節點配置爲DO,只要網絡再次可用,就自動同步它們的狀態? – 2013-04-08 08:20:51

+1

不是我所知(除非在更新版本的RabbitMQ中可用...我至少還沒有檢查過一年)。 – 2013-09-11 03:35:26

6

RabbitMQ還提供了兩種自動處理網絡分區的方式:暫停少數模式和自動模式。 (默認行爲被稱爲忽略模式)。

暫停少數模式RabbitMQ會在看到其他節點關閉後自動暫停確定自己處於少數(即少於或等於節點總數一半)的羣集節點。因此,它從CAP定理中選擇對可用性的分區容差。這確保了在網絡分區的情況下,單個分區中的節點至多將繼續運行。

在自動模式下,如果分區被視爲已經發生,RabbitMQ將自動決定獲勝的分區。它將重新啓動不在獲勝分區中的所有節點。獲勝的分區是其具有最 自動處理分區

客戶端連接(或者如果這產生平局,具有最節點之一;以及如果仍可產生平局,則分區中的一個是以未指定的方式選擇)。

您可以通過將配置文件中的兔子應用程序的配置參數cluster_partition_handling設置爲pause_minority或autoheal來啓用任一模式。

我應該選擇哪種模式?

理解允許RabbitMQ自動處理網絡分區並不能減少問題是很重要的。網絡分區總是會給RabbitMQ集羣帶來問題;你只是在某種程度上選擇了你遇到的問題。如前言所述,如果您想通過通常不可靠的鏈接連接RabbitMQ羣集,則應使用聯合身份驗證或鏟。

雖這麼說,你不妨選擇一個恢復模式如下:

  • 忽略 您的網絡真的是可靠的。你所有的節點都在一個機架上,與交換機相連,而且這個交換機也是通向外部世界的路由。如果任何其他部分失敗(或者您有兩個節點羣集),則不希望發生任何羣集關閉的風險。

  • pause_minority 您的網絡可能不太可靠。你在EC2中聚集了3個AZ,並且你認爲只有一個AZ會一次失敗。在這種情況下,您希望剩餘的兩個AZ繼續工作,並且失敗的AZ中的節點可以在AZ返回時自動重新加入,而不會大驚小怪。

  • autoheal 您的網絡可能不夠穩定。與數據完整性相比,您更關心服務的連續性。您可能有兩個節點羣集。

此答案來自rabbitmq文檔。 https://www.rabbitmq.com/partitions.html會給你更詳細的描述。