RabbitMQ集群(鏡像隊列)原理詳解


鏡像集群模式(RabbitMQ的HA方案)

rabbitmq鏡像集群依賴於普通集群,所以需要先搭建rabbitmq普通集群

鏡像集群模式其實就是把需要的隊列做成鏡像隊列,然后將鏡像隊列放在多個節點當中,這種鏡像集群模式解決了普通集群模式沒有做到的高可用性的缺點,鏡像集群模式屬於Rabbit MQ的高可用性的集群部署方案。

 

普通隊列進程及其內容僅僅維持在單個節點之上,所以一個節點的失效表現為其對應的隊列不可用。
引入鏡像隊列(Mirror Queue)的機制,可以將隊列鏡像到集群中的其他Broker節點之上,如果集群中的一個節點失效了,隊列能夠自動切換到鏡像中的另一個節點上以保證服務的可用性。
針對每個隊列的(以下簡稱鏡像隊列)都包含一個主節點(master)和若干個從節點(slave)

 

 由圖可知master和slave組成了一個鏈表結構。
slave會准確地按照maste執行命令地順序進行動作,故slave和master上維護的狀態應該是相同的。如果master由於某種原因失效,那么“資歷最老”(基於slave加入cluster的時間排序)的slave會被提升為新的master。發送到鏡像隊列的所有消息會被同時發往 master和所有的slave上,如果此時master掛掉了,消息還會在slave上,這樣slave提升為 master的時候消息也不會丟失

集群中的每個 Broker 節點都包含 1 個隊列的 master 和 2 個隊列的 slave, Q1 的負載大多都在 broker1 上,Q2 的負載大多都集中在 broker2 上,Q3 的負載大多都集中在 broker3 上,只要確保隊列的 master 節點均勻散落在集群中的各個 Broker 節點即可確保很大程度的負載均衡。

master提供讀寫服務,在slave上的操作都會路由到master上,slave只做備份-主備切換

RabbitMQ 的鏡像隊列同時支持publisher confirm和事務兩種機制

當slave掛掉之后,除了與slave相連的客戶端連接全部斷開,沒有其他影響
當master掛掉之后,會有以下影響:

  1. 與master連接的客戶端連接全部斷開;
  2. 選舉最老的slave作為新的master,因為最老的slave與舊的master之間的同步狀態應該是最好的。如果此時所有slave處於未同步狀態,則未同步的消息會丟失;
  3. 新的master重新入隊所有unack的消息,因為新的slave無法區分這些unack的消息是否己經到達客戶端,或者是ack信息丟失在老的master鏈路上,再或者是丟失在老的master 組播ack消息到所有slave的鏈路上,所以出於消息可靠性的考慮,重新入隊所有unack的消息,不過此時客戶端可能會有重復消息;
  4. 如果客戶端連接着slave,並且Basic.Consume 消費時指定了x-cancel-on-ha-failover 參數,那么斷開之時客戶端會收到一個Consumer Cancellation Notification的通知,消費者客戶端中會回調Consumer接口的handleCancel方法。如果未指定x-cancel-on-ha-failover參數,那么消費者將無法感知 master 宕機;

當所有slave都出現未同步狀態,並且ha-prornote-on-shutdown設置為when-synced(默認)時,如果master因為主動原因停掉,比如通過rabbitrnqctl stop命令或者優雅關閉操作系統,那么slave不會接管master,也就是此時鏡像隊列不可用。但是如果master因為被動原因停掉,比如Erlang虛擬機或者操作系統崩潰,那么slave會接管master。這個配置項隱含的價值取向是保證消息可靠不丟失,同時放棄了可用性。如果ha-prornote-on-shutdown設置為always ,那么不論master因為何種原因停止,slave都會接管master,優先保證可用性,不過消息可能會丟失。

鏡像隊列中最后一個停止的節點會是master,啟動順序必須是master先啟動。如果slave先啟動,它會有30 秒的等待時間,等待master的啟動,然后加入到集群中。如果30 秒內 master沒有啟動,slave會自動停止。當所有節點因故(斷電等)同時離線時,每個節點都認為自己不是最后一個停止的節點,要恢復鏡像隊列,可以嘗試在30秒內啟動所有節點。

 

鏡像隊列間的消息流轉

當消費者與master隊列建立連接,消費者可以直接從master隊列上獲取信息,當消費者與slave隊列建立連接呢?消費者是從slave隊列直接獲取數據的嗎?當然不是的,消息的流轉順序如下所示:

  • slave隊列先將消費者的請求轉發給master隊列
  • 然后再由master隊列准備好數據返回給slave隊列
  • 最后由slave隊列將消息返回給消費者

那這樣就會有一個疑問?消費者的請求都是由master隊列進行處理的,那么消息的負載是不是不能夠做到有效的均衡呢?

負載均衡

Rabbit MQ的負載均衡是體現在物理機器層面上的,而不是體現在內存中的隊列層面的。這樣解釋吧,現在有3台物理機,需要創建3個master隊列和6個slave隊列, 消息的請求負載都在3個master隊列上,那么只需要將3個master隊列和6個slave隊列均勻的分布在3台物理機上,這樣在很大程度上實現了每台機器的負載均衡。當然每個master隊列消息請求的數量可能會有不同,無法保持絕對的負載均衡。

消息的可靠性

RabbitMQ的鏡像隊列使用 publisher confirm 和事務兩種機制來保證其消息的可靠性。在事務機制中,只有當前事務在全部鏡像中執行之后,客戶端才會收到 Tx Commit-Ok 的消息。同樣的,在 publisher confirm 機制中,生產者進行當前消息確認的前提是該消息被全部進行所接收了。

鏡像集群模式總結

鏡像隊列的引入可以極大地提升 RabbitMQ 的可用性及可靠性,提供了數據冗余備份、避免單點故障的功能,因此推薦在實際應用中為每個重要的隊列都配置鏡像。

說了這么多的鏡像隊列的優點,那么鏡像隊列就沒有缺點了嗎?當然不是,那么鏡像集群的缺點是什么呢?

首先鏡像隊列需要為每一個節點都要同步所有的消息實體,所以會導致網絡帶寬壓力很大。 提供了數據的冗余備份,會導致存儲壓力變大,可能會出現IO瓶頸。

總結

普通集群模式增加了RabbitMq系統的吞吐量,但不能實現系統的高可用,如果磁盤節點崩潰可能會導致數據丟失,不能再對隊列、交換器、綁定關系、用戶進行更改,更改權限、添加或刪除集群節點也不能操作。鏡像集群模式是RabbitMq的HA部署方案,極大地提升 RabbitMQ 的可用性及可靠性,提供了數據冗余備份、避免單點故障的功能。但是鏡像隊列需要為每一個節點都要同步所有的消息實體,所以會導致網絡帶寬壓力很大。 提供了數據的冗余備份,會導致存儲壓力變大,可能會出現IO瓶頸。具體怎樣選擇還需要使用者根據實際的業務場景選擇合適的部署方案。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM