一、目的
允許消費者和生產者在RabbitMQ節點崩潰的情況下繼續運行
通過增加更多的節點來擴展消息通信的吞吐量
二、RabbitMQ可以通過三種方法來部署分佈式集羣系統
cluster:
不支持跨網段,用於同一個網段內的局域網
可以隨意的動態增加或者減少
節點之間需要運行相同版本的RabbitMQ和Erlang
federation:
應用於廣域網,允許單臺服務器上的交換機或隊列接收發布到另一臺服務器上交換機或隊列的消息,可以是單獨機器或集羣。federation隊列類似於單向點對點連接,消息會在聯盟隊列之間轉發任意次,直到被消費者接受。通常使用federation來連接internet上的中間服務器,用作訂閱分發消息或工作隊列。
shovel:
連接方式與federation的連接方式類似,但它工作在更低層次。可以應用於廣域網。
三、節點類型
RAM node:
內存節點將所有的隊列、交換機、綁定、用戶、權限和vhost的元數據定義存儲在內存中,好處是可以使得像交換機和隊列聲明等操作更加的快速。
Disk node:
將元數據存儲在磁盤中,單節點系統只允許磁盤類型的節點,防止重啓RabbitMQ的時候,丟失系統的配置信息。
問題說明: RabbitMQ要求在集羣中至少有一個磁盤節點,所有其他節點可以是內存節點,當節點加入或者離開集羣時,必須要將該變更通知到至少一個磁盤節點。如果集羣中唯一的一個磁盤節點崩潰的話,集羣仍然可以保持運行,但是無法進行其他操作(增刪改查),直到節點恢復。
解決方案:設置兩個磁盤節點,至少有一個是可用的,可以保存元數據的更改。
注意點:
如果是唯一的磁盤節點也發生故障了,集羣可以繼續路由消息,但是不可以做以下操作了:
- 創建隊列
- 創建交換器
- 創建綁定
- 添加用戶
- 更改權限
- 添加或刪除集羣節點
四、 Erlang Cookie
Erlang Cookie是保證不同節點可以相互通信的密鑰,要保證集羣中的不同節點相互通信必須共享相同的Erlang Cookie。具體的目錄存放在/var/lib/rabbitmq/.erlang.cookie。
說明: 這就要從rabbitmqctl命令的工作原理說起,RabbitMQ底層是通過Erlang架構來實現的,所以rabbitmqctl會啓動Erlang節點,並基於Erlang節點來使用Erlang系統連接RabbitMQ節點,在連接過程中需要正確的Erlang Cookie和節點名稱,Erlang節點通過交換Erlang Cookie以獲得認證。
五、 鏡像隊列
功能和原理
RabbitMQ的Cluster集羣模式一般分爲兩種,普通模式和鏡像模式。
普通模式:
當消息進入A節點的Queue中後,consumer從B節點拉取時,RabbitMQ會臨時在A、B間進行消息傳輸,把A中的消息實體取出並經過B發送給consumer,所以consumer應平均連接每一個節點,從中取消息。該模式存在一個問題就是當A節點故障後,B節點無法取到A節點中還未消費的消息實體。如果做了隊列持久化或消息持久化,那麼得等A節點恢復,然後纔可被消費,並且在A節點恢復之前其它節點不能再創建A節點已經創建過的持久隊列;如果沒有持久化的話,消息就會失丟。這種模式更適合非持久化隊列,只有該隊列是非持久的,客戶端才能重新連接到集羣裏的其他節點,並重新創建隊列。假如該隊列是持久化的,那麼唯一辦法是將故障節點恢復起來。
爲什麼RabbitMQ不將隊列複製到集羣裏每個節點呢?這與它的集羣的設計本意相沖突,集羣的設計目的就是增加更多節點時,能線性的增加性能(CPU、內存)和容量(內存、磁盤)。
鏡像模式:
將需要消費的隊列變爲鏡像隊列,存在於多個節點,這樣就可以實現RabbitMQ的HA高可用性。作用就是消息實體會主動在鏡像節點之間實現同步,而不是像普通模式那樣,在consumer消費數據時臨時讀取。缺點就是,集羣內部的同步通訊會佔用大量的網絡帶寬。
實現機制
鏡像隊列實現了RabbitMQ的高可用性(HA),具體的實現策略如下所示:
ha-mode | ha-params | 功能 |
all | 空 | 鏡像隊列將會在整個集羣中複製。當一個新的節點加入後,也會在這 個節點上覆制一份。 |
exactly | count | 鏡像隊列將會在集羣上覆制count份。如果集羣數量少於count時候,隊列會複製到所有節點上。如果大於Count集羣,有一個節點crash後,新進入節點也不會做新的鏡像。 |
nodes | node name | 鏡像隊列會在node name中複製。如果這個名稱不是集羣中的一個,這不會觸發錯誤。如果在這個node list中沒有一個節點在線,那麼這個queue會被聲明在client連接的節點 |
實例列舉:
queue_args("x-ha-policy":"all") //定義字典來設置額外的隊列聲明參數
channel.queue_declare(queue="hello-queue",argument=queue_args)
如果需要設定特定的節點(以rabbit@localhost爲例),再添加一個參數
queue_args("x-ha-policy":"nodes",
"x-ha-policy-params":["rabbit@localhost"])
channel.queue_declare(queue="hello-queue",argument=queue_args)
可以通過命令行查看那個主節點進行了同步
rabbitmqctl list_queue name slave_pids synchronised_slave_pids