RabbitMQ集群(普通隊列)原理詳解


RabbitMQ是基於Erlang編寫,Erlang語言天生具備分布式特性(通過同步Erlang集群各節點的magic cookie來實現)。因此,RabbitMQ天然支持Clustering。這使得RabbitMQ本身不需要像ActiveMQ、Kafka那樣通過ZooKeeper分別來實現HA高可用方案和保存集群的元數據。集群是保證可靠性的一種方式,同時可以通過水平擴展以達到增加消息吞吐量能力的目的。

【普通模式】
普通集群模式就是將多台Rabbit MQ服務器連接組成一個集群,在連接過程中需要正確的Erlang Cookie和節點名稱才能保證機器之間相互進行連接訪問,並且集群需要要局域網內進行部署。

一、RabbitMQ集群元數據的同步

Rabbit MQ的集群不是每個節點都有所有隊列的完全拷貝。交換機的元數據信息在所有節點上都是一致的,但是存放消息的隊列的完整信息都只存在它所創建的節點上,所有其他節點只知道隊列的元數據和指向該隊列存在的那個節點的指針,元數據信息包括以下內容:

RabbitMQ集群會始終同步四種類型的內部元數據:
1.隊列元數據:隊列名稱、屬性;
2.交換器元數據:交換器名稱、類型和屬性;
3.綁定元數據:交換器與隊列綁定關系,如binding_key;
4.vhost元數據:虛擬主機內部配置和屬性;
因此,當用戶訪問其中任何一個RabbitMQ節點時,通過rabbitmqctl查詢到的queue/user/exchange/ vhost等信息都是相同的。

注意:隊列只同步元數據信息,不會同步存儲的消息,消息只會存在於創建該隊列的節點上,其它節點只知道這個隊列的元數據信息和一個指向隊列的owner node的地址。

二、為何RabbitMQ集群僅采用元數據同步的方式

RabbitMQ這么設計主要是基於集群本身的性能和存儲空間上來考慮。
第一,存儲空間,如果每個集群節點都擁有所有Queue的完全數據拷貝,那么每個節點的存儲空間會非常大,集群的消息積壓能力會非常弱(無法通過集群節點的擴容提高消息積壓能力);
第二,性能,消息的發布者需要將消息復制到每一個集群節點,對於持久化消息,網絡和磁盤同步復制的開銷都會明顯增加。

三、集群節點間的消息流轉

以三個節點(node1、node2、node3)的集群為例來進行說明。消息實體是存在於隊列之中的,而節點之間只有相同的元數據信息,假設消息存在於node1節點的A隊列上,當消費者從node2節點上的B隊列消費時,這時RabbitMQ會臨時在node1和node2節點進行消息傳輸,把A隊列上的消息實體傳到B隊列上,然后發送給消費者。

這個過程其實會對node1節點產生性能瓶頸,因為無論consumer連node1或node2,都會從node1拉取數據。針對這種情況,有一個中庸的做法就是將consumer盡量連接每一個節點。

四、集群節點類型

集群節點類型分為以下兩類:

磁盤節點
內存節點
磁盤節點的數據信息是存儲在磁盤上的,內存節點的信息是存儲在內存上的,因此內存節點的性能要高於磁盤節點。

注意: Rabbit MQ要求集群中至少有一個磁盤節點,所有其他節點可以是內存節點,當節點加入和離開集群時,必須通知磁盤節點。

當唯一的磁盤節點崩潰時,

集群可以繼續發送或者接收消息, 但是不能執行創建隊列、交換器、綁定關系、用戶,以及更改權限、添加或刪除集群節點的操作了。 也就是說,如果集群中唯一的磁盤節點崩潰,集群仍然可以保持運行,但是直到將該節點恢復到集群前,你無法更改任何東西。所以在建立集群的時候應該保證有兩個或者多個磁盤節點的存在。

五、集群節點異常處理

當集群節點崩潰時,該節點的隊列進程和關聯的綁定都會消失。附加在那些隊列上的消費者 會丟失其所訂閱的信息 井且任何匹配該隊列綁定信息的新消息也都會消失。那么面臨這種情況應該如何處理呢:

持久化處理,當該節點重啟的時候可以再次獲取到該消息。
使用鏡像模式,就是指創建一個鏡像節點,鏡像節點保存有崩潰節點的所有信息,那么該節點崩潰時,鏡像節點可以接替它繼續工作,直至崩潰節點重啟。

六、RabbitMQ集群的基本原理

 

 

 


場景1、客戶端直接連接隊列所在節點
如果有一個消息生產者或者消息消費者通過amqp-client的客戶端連接至節點1進行消息的發布或者訂閱,那么此時的集群中的消息收發只與節點1相關。

場景2、客戶端連接的是非隊列數據所在節點
如果消息生產者所連接的是節點2或者節點3,此時隊列1的完整數據不在該兩個節點上,那么在發送消息過程中這兩個節點主要起了一個路由轉發作用,根據這兩個節點上的元數據(也就是上文提到的:指向queue的owner node的指針)轉發至節點1上,最終發送的消息還是會存儲至節點1的隊列1上。
同樣,如果消息消費者所連接的節點2或者節點3,那這兩個節點也會作為路由節點起到轉發作用,將會從節點1的隊列1中拉取消息進行消費。

由於節點之間存在路由轉發的情況,所以對於RabbitMQ集群最好是在一個局域網。

 

七、普通集群模式總結:

多機集群提高了系統的吞吐量和可靠性。但是並沒有做到高可用性,因為當磁盤節點崩潰的話,其它節點不能進行創建隊列、創建交換器等,可以這樣說吧,其它內存節點就是為磁盤節點服務的,下面介紹的鏡像模式部署解決了這個缺點,實現了集群的高可用性。

1、在哪台服務器創建的exchange,queue,那哪台服務器就存儲的就是原始數據,其他服務器存儲的只是這台服務器的引用地址;

2、不管在哪個服務器往queue添加消息,只看queue是在哪台服務器創建的,數據本身就會存入對應的服務器上,而不是添加時連接的服務器;同理,消費者在消費時不管從哪台服務器讀取,最終都是從數據本身的服務器上讀取

例:server1:創建exchange,queue; server2:給queue添加消息;添加后消息會存入server1而不是存入server2,server2還是只保存引用;消費消息連接server2,會從server1把消息拿到server2,在傳輸給消費者

3、如果server1宕機了,該機器上的存儲的消息都將不可讀取,如果有做持久化,等服務器重啟后會自動恢復;

4、普通模式不是高可用模式,針對不是那么強一致性的業務可用,相對來說吞吐量高一些;

5、使用普通模式,不要把exchange,queue創建在同一台服務器上,要均勻分布,否則某一台掛了,會導致整個集群都宕掉;或者使用代理和負載均衡處理;

 


免責聲明!

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



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