| 
 在上一篇中,我們已經(jīng)詳細(xì)介紹了RabbitMQ的發(fā)展歷程與AMQP協(xié)議中的相關(guān)概念 ,接下來,我們開始進(jìn)入高級篇的部分,深入介紹如何搭建RabbitMQ集群,以及在RabbitMQ集群中做插件管理、構(gòu)建HA方案、如何實現(xiàn)通過RabbitMQ支撐高并發(fā)的大規(guī)模生產(chǎn)集群,本文中將深入解析RabbitMQ服務(wù)器與集群。 一、RabbitMQ 服務(wù)器 
 如何查看RabbitMQ當(dāng)前的運行狀態(tài)? 在部署好的集群當(dāng)中,您可以通過rabbitmqctl status可以查看到RabbitMQ的狀態(tài)。 上圖中,紅框內(nèi)為運行的應(yīng)用。 Rabbit即為RabbitMQ 服務(wù)器。其余則為Erlang/OTP提供的application。 · os_mon: operating system monitor,操作系統(tǒng)監(jiān)控 · xmerl: Functions for exporting XML data to an external format,導(dǎo)出XML數(shù)據(jù)到外部格式 · mnesia: a distributed DataBase Management System (DBMS), appropriate for telecommunications applications and other Erlang applications which require continuous operation and exhibit soft real-time properties. 一個分布式數(shù)據(jù)庫管理系統(tǒng),適合于電信應(yīng)用和其他需要持續(xù)操作并展示實時信息的應(yīng)用 · SASL (System Architecture Support Libraries) · Kernel & stdlib: The Kernel application is the first application started. It is mandatory in the sense that the minimal system based on Erlang/OTP consists of Kernel and STDLIB. 是第一個啟動的服務(wù),其作為Erlang框架的核心。 注:以上Erlang/OTP的應(yīng)用都可以通過 “erl –man ”查詢它的幫助文檔。 如何啟動RabbitMQ服務(wù)? RabbitMQ 服務(wù)器是通過erl啟動,啟動時需要進(jìn)行一系列的應(yīng)用參數(shù)配置: 如上圖所示,配置的參數(shù)包括了節(jié)點名稱,配置,日志,插件等等 RabbitMQ 服務(wù)啟動后,會運行哪些進(jìn)程? epmd(Erlang Port Mapper Daemon): · Erlang Port Mapper Daemon (epmd). 當(dāng)啟動分布式的Erlang node時,epmd將記錄IP/Port信息。 當(dāng)使用rabbitmqctl join_cluster將Erlang node連接成集群時,epmd負(fù)責(zé)節(jié)點名稱和IP/Port的轉(zhuǎn)換。 Beam.smp: RabbitMQ創(chuàng)建的眾多處理消息的線程。 如何設(shè)置防火墻? 由于RabbitMQ中上述的應(yīng)用都在監(jiān)聽不同的端口,如果rabbitmq-server所在的節(jié)點需要進(jìn)行防火墻設(shè)置,則需要打開如下端口: 如何管理RabbitMQ? RabbitMQ提供的唯一操作工具就是rabbitmqctl。除了常規(guī)的queue/exchange/policy/user/permission等操作外,可以利用它的“eval”子命令,來擴(kuò)展出很多功能。比如查詢net_ticktime / erlang cookie。 如何選擇RabbitMQ的消息保存方式? RabbitMQ對于queue中的message的保存方式有兩種方式:disc和ram。如果采用disc,則需要對exchange/queue/delivery mode都要設(shè)置成durable模式。Disc方式的好處是當(dāng)RabbitMQ失效了,message仍然可以在重啟之后恢復(fù)。而使用ram方式,RabbitMQ處理message的效率要高很多,ram和disc兩種方式的效率比大概是3:1。所以如果在有其它HA手段保障的情況下,選用ram方式是可以提高消息隊列的工作效率的。 如果使用ram方式,RabbitMQ能夠承載的訪問量則取決于可用的內(nèi)存數(shù)了。RabbitMQ使用兩個參數(shù)來限制使用系統(tǒng)的內(nèi)存,避免系統(tǒng)被自己獨占。 vm_memory_high_watermark:表示RabbitMQ使用內(nèi)存的上限為系統(tǒng)內(nèi)存的40%。也可以通過absolute參數(shù)制定具體可用的內(nèi)存數(shù)。當(dāng)RabbitMQ使用內(nèi)存超過這個限制時,RabbitMQ 將對消息的發(fā)布者進(jìn)行限流,直到內(nèi)存占用回到正常值以內(nèi)。 Vm_memory_high_watermark_paging_ratio:表示當(dāng)RabbitMQ達(dá)到0.4*0.75=30%,系統(tǒng)將對queue中的內(nèi)容啟用paging機(jī)制,將message等內(nèi)容換頁到disk 中。 RabbitMQ的內(nèi)存使用情況可以通過“rabbitmqctl status”或者管理插件中的Web UI查詢。 各個內(nèi)存條目的含義請參照:https://www./memory-use.html 當(dāng)消息發(fā)送的速率超過了RabbitMQ的處理能力時該怎么辦? RabbitMQ會自動減慢這個連接的速率,讓client端以為網(wǎng)絡(luò)帶寬變小了,發(fā)送消息的速率會受限,從而達(dá)到流控的目的。 使用”rabbitmqctl list_connections”查看連接,如果狀態(tài)為“flow”,則說明這個連接處于flow-control 狀態(tài)。 RabbitMQ集群 RabbitMQ基于Erlang編寫,天然支持clustering。集群是保證可靠性的一種方式,同時可以通過水平擴(kuò)展以達(dá)到增加消息吞吐能力的目的。 上圖中是三個節(jié)點的RabbitMQ集群,Exchange A的metadata信息在所有節(jié)點上是一致的,queue的完整信息則只在它創(chuàng)建的那個節(jié)點上。每個RabbitMQ節(jié)點通常以“rabbit@”表示,所以hostname在運行RabbitMQ的節(jié)點中很重要。注意:如果更改了hostname,需要重置RabbitMQ內(nèi)部的數(shù)據(jù)庫,否則服務(wù)無法工作。 如何構(gòu)建集群? 單個rabbitmq-server啟動之后,在確保Erlang cookie相同的情況下,可以通過 將幾個RabbitMQ節(jié)點連接成集群。RabbitMQ集群由Erlang/OTP提供的通訊機(jī)制保證集群節(jié)點之間的通訊。從邏輯上講,RabbitMQ集群是單一的message broker,消息隊列消費者連接集群中的任一個節(jié)點都可以。如果配合HAProxy,client只需要訪問單一一個地址,由HAProxy負(fù)責(zé)load balance,將訪問請求分發(fā)給各個節(jié)點。 如果單純做試驗,也可以在一個虛擬機(jī)上啟動三個RabbitMQ的實例,只要在啟動時通過設(shè)置RABBITMQ_NODE_PORT讓三個實例監(jiān)聽不同端口即可。 RabbitMQ維護(hù)著四種類型的metadata: queue/exchange/binding/vhost,在集群中這些信息被同步到每個節(jié)點,因此當(dāng)用戶訪問任何一個節(jié)點時,通過rabbitmqctl查詢到的queue/user/exchange等信息都是相同的。 通常我們將這些信息保存到磁盤上,也就是查詢RabbitMQ狀態(tài)時的“disc”方式,以便集群重啟時可以根據(jù)保存的metadata信息重建exchange等。 對于exchange來講,它的所有信息就是一個exchange名字加上一個查詢表。查詢表中記錄了所有的queue binding。當(dāng)message被發(fā)送到exchange時,client連接的channel對routing key進(jìn)行比對,根據(jù)binding進(jìn)行正確的轉(zhuǎn)發(fā)。 對于Queue來講,雖然它的metadata在每個節(jié)點上都有,但只有在它被創(chuàng)建的那個RabbitMQ 節(jié)點上才具有完整的信息:比如state/contents等,這個node被稱為此queue的owner node。其他節(jié)點只知道這個queue的metadata信息和一個指向queue的owner node的指針。 如果一個client訪問RabbitMQ的節(jié)點上沒有需要的queue的完整信息,RabbitMQ將根據(jù)這個指針將請求轉(zhuǎn)發(fā)到owner node。 這張圖上可以看到,Exchange的所有信息被復(fù)制到集群中的所有節(jié)點,“Queue 1”的metadata被復(fù)制到每個節(jié)點,但它的完整信息(content)只存在于一個節(jié)點上,也就是這個queue的owner node。 Mnesia是RabbitMQ中的數(shù)據(jù)庫,它是內(nèi)嵌在Erlang中的no-SQL數(shù)據(jù)庫。Exchange/Queue/Binding等的metadata信息都保存在mnesia的數(shù)據(jù)庫文件中。關(guān)于RabbitMQ的集群信息也保存在這里。Rabbitmqctl的reset操作實際上就是清空了mnesia數(shù)據(jù)庫所在目錄的內(nèi)容。 RabbitMQ集群模式 除了上面講到的RabbitMQ 內(nèi)嵌的clustering方式進(jìn)行分布式的消息處理,RabbitMQ還有federation/shovel兩種分布式方式,這兩種方式以RabbitMQ plugin的形式存在。RabbitMQ對網(wǎng)絡(luò)延遲很敏感,在單個數(shù)據(jù)中心中使用clustering方式。在WAN環(huán)境中,則使用Federation或Shovel。 以Shovel為例,在rabbitmq.conf中定義rabbitmq_shovel的配置,主要是對兩個獨立RabbitMQ 節(jié)點中,定義源和目的節(jié)點中exchange/queue的replication關(guān)系。當(dāng)一個請求發(fā)送到源RabbitMQ節(jié)點時,先響應(yīng)請求,之后根據(jù)replication關(guān)系,shovel會異步的將message傳送到目的RabbitMQ節(jié)點進(jìn)行處理。 這里對federation/shovel聯(lián)邦模式跟clustering集群模式一個簡單的對比。 
 | 
|  |