RabbitMQ內建集群的設計用於完成兩個目標:允許消費者和生產者在RabbitMQ節點在奔潰的情況下繼續運行,以及通過添加更多的節點來線性擴展消息通信的吞吐量。當失去一個RabbitMQ節點時客戶端能夠連接集群中的任何其他節點並繼續生產或者消費消息。同樣,如果RabbitMQ集群正疲於應對龐大的消息通信量,可以通過添加更過的節點線性增加性能。
RabbitMQ集群不會保證消息的萬無一失:因為RabbitMQ默認不會將隊列的內容復制到整個集群上。如果不進行特殊的配置,這些消息僅存在隊列所屬的那個節點上。
RabbitMQ集群架構
RabbitMQ會始終記錄以下四種類型的內部元數據:
- 隊列元數據-隊列名稱即其他屬性
- 交換器元數據-交換器名稱、類型、屬性
- 綁定元數據-一張簡單的表格展示如何將消息路由到隊列
- Vhost元數據-為vhost內的隊列、交換器和綁定提供命名空間和安全屬性
在單一節點中,RabbitMQ會將這些元數據信息存儲在硬盤中,同時哪些標記為可持久化的隊列和交換器(以及它們的綁定)存儲在硬盤上。存儲在硬盤和交換器和隊列在重啟RabbitMQ后重新重建。當引入集群時,RabbitMQ需要跟蹤新的元數據類型:集群節點位置、以及節點與已記錄的其他類型元數據的關系。
集群中的隊列
在RabbitMQ集群中,不是每一個節點都有所有隊列的完全拷貝。如果在集群中創建隊列的話,集群只會在單個節點而不是在所有節點上創建完整的隊列信息(元數據、狀態和內容)。結果是只有隊列的所有者節點知道有關隊列的所有信息。所有其他非所有者節點只知道隊列的元數據和指向該隊列存在的那個節點的指針。因此當集群節點奔潰是,該節點的隊列和關聯的綁定就都消失了。附加在隊列的消費者也丟失了訂閱信息,並且任何匹配該隊列綁定信息的新消息也都丟失了。可以通過讓消費者重新連接到集群並重新創建隊列。但是這種做法僅對當隊列最開始沒有被設置成可持久化才行。

為什么在默認情況下RabbitMQ不將隊列內容和狀態復制到所有的節點呢?
- 存儲空間
- 性能,減少網絡和磁盤負載。
分布交換器
交換器是一個名稱和一個隊列綁定的列表。當消息發布到交換器時,實際是由連接到的信道將消息上路由鍵同交換器的綁定進行比較,然后路由消息。
當創建一個新的交換器時,RabbitMQ所要做的是將查詢表添加到集群中的所有節點上。
如果消息已經發布到信道上,但在消息路由之前節點發生故障的這些消息會怎樣?
AMQP的basic.publish命令不會返回消息的狀態。這種情況意味着消息將會丟失。解決方案是使用AMQP事務,在消息路由到隊列之前一直它會一直阻塞;或者使用發送發確認模式來記錄連接中斷是尚未被確認的消息。
內存節點和磁盤階段
內存階段:將所有隊列、交換器、綁定、用戶、權限和Vhost的元數據定義都出處在內存中。而磁盤節點則將元數據存儲在磁盤中。單節點系統只允許磁盤類型的節點:否則每次重啟RabbitMQ后,所有關於系統的配置信息都會丟失。
RabbitMQ只要求集群中至少有一個磁盤節點,其他節點都可以是內存節點。當節點加入或者離開集群時,它們必須要將變更通知到至少一個磁盤節點。如果只有一個磁盤節點,磁盤節點奔潰后,集群可以繼續路由消息(即保持運行),但是直到該節點恢復之前,無法更改任何東西。通常在集群中設置兩個磁盤節點。
