一、RabbitMQ簡介
1.1 RabbitMQ是什么
RabbitMQ是一個開源的AMQP實(shí)現(xiàn),服務(wù)器端用Erlang語言編寫,支持多種客戶端木蹬,如:Python、Ruby氏涩、.NET届囚、Java有梆、JMS是尖、C、PHP泥耀、ActionScript饺汹、XMPP、STOMP等痰催,支持AJAX兜辞。用于在分布式系統(tǒng)中存儲轉(zhuǎn)發(fā)消息迎瞧,在易用性、擴(kuò)展性逸吵、高可用性等方面表現(xiàn)不俗凶硅。
1.2 RabbitMQ特點(diǎn)
(1)可靠性(Reliability)RabbitMQ 使用一些機(jī)制來保證可靠性,如持久化扫皱、傳輸確認(rèn)足绅、發(fā)布確認(rèn)。
(2)靈活的路由(Flexible Routing)在消息進(jìn)入隊(duì)列之前韩脑,通過 Exchange 來路由消息的氢妈。對于典型的路由功能,RabbitMQ 已經(jīng)提供了一些內(nèi)置的 Exchange 來實(shí)現(xiàn)段多。針對更復(fù)雜的路由功能首量,可以將多個 Exchange 綁定在一起,也通過插件機(jī)制實(shí)現(xiàn)自己的 Exchange 进苍。
(3)消息集群(Clustering)多個 RabbitMQ 服務(wù)器可以組成一個集群加缘,形成一個邏輯 Broker 。
(4)高可用(Highly Available Queues)隊(duì)列可以在集群中的機(jī)器上進(jìn)行鏡像觉啊,使得在部分節(jié)點(diǎn)出問題的情況下隊(duì)列仍然可用生百。
(5)多種協(xié)議(Multi-protocol)RabbitMQ 支持多種消息隊(duì)列協(xié)議,比如 STOMP柄延、MQTT 等等蚀浆。
(6)多語言客戶端(Many Clients)RabbitMQ 幾乎支持所有常用語言,比如 Java搜吧、.NET市俊、Ruby 等等。
(7)管理界面(Management UI)RabbitMQ 提供了一個易用的用戶界面滤奈,使得用戶可以監(jiān)控和管理消息 Broker 的許多方面摆昧。
(8)跟蹤機(jī)制(Tracing)如果消息異常,RabbitMQ 提供了消息跟蹤機(jī)制蜒程,使用者可以找出發(fā)生了什么绅你。
(9)插件機(jī)制(Plugin System)RabbitMQ 提供了許多插件,來從多方面進(jìn)行擴(kuò)展昭躺,也可以編寫自己的插件忌锯。
1.3 RabbitMQ 解決什么問題
(1)你是否遇到過兩個(多個)系統(tǒng)間需要通過定時(shí)任務(wù)來同步某些數(shù)據(jù)?你是否在為異構(gòu)系統(tǒng)的不同進(jìn)程間相互調(diào)用领炫、通訊的問題而苦惱偶垮、掙扎?
(2)在Web應(yīng)用高并發(fā)環(huán)境下,由于來不及同步處理似舵,請求往往會發(fā)生堵塞脚猾。比如說,大量的insert砚哗、update請求同時(shí)到達(dá)mysql龙助,會帶來無數(shù)的行鎖表鎖,最后導(dǎo)致請求數(shù)過多蛛芥,觸發(fā)too many connections錯誤泌参。
(3)消息服務(wù)擅長于解決多系統(tǒng)、異構(gòu)系統(tǒng)間的數(shù)據(jù)交換(消息通知/通訊)問題常空,你也可以把它用于系統(tǒng)間服務(wù)的相互調(diào)用(RPC)通過使用消息隊(duì)列沽一,我們可以異步處理請求,從而緩解系統(tǒng)的壓力漓糙。
1.4 RabbitMQ 應(yīng)用場景
對于一個大型的軟件系統(tǒng)來說铣缠,它會有很多的組件或者說模塊或者說子系統(tǒng)或者(Subsystem or Component or Submodule)。那么這些模塊的如何通信昆禽?這和傳統(tǒng)的IPC有很大的區(qū)別蝗蛙。傳統(tǒng)的IPC很多都是在單一系統(tǒng)上的,模塊耦合性很大醉鳖,不適合擴(kuò)展(Scalability)捡硅;如果使用socket那么不同的模塊的確可以部署到不同的機(jī)器上,但是還是有很多問題需要解決盗棵。比如:
(1)信息的發(fā)送者和接收者如何維持這個連接壮韭,如果一方的連接中斷,這期間的數(shù)據(jù)如何方式丟失纹因?
(2)如何降低發(fā)送者和接收者的耦合度喷屋?
(3)如何讓Priority高的接收者先接到數(shù)據(jù)?
(4)如何做到Load balance瞭恰?有效均衡接收者的負(fù)載屯曹?
(5)如何有效的將數(shù)據(jù)發(fā)送到相關(guān)的接收者?也就是說將接收者subscribe不同的數(shù)據(jù)惊畏,如何做有效的filter恶耽。
(6)如何做到可擴(kuò)展,甚至將這個通信模塊發(fā)到cluster上颜启?
(7)如何保證接收者接收到了完整偷俭,正確的數(shù)據(jù)?
1.5 RabbitMQ 集群方式
(1)普通模式:默認(rèn)的集群模式农曲。?對于Queue來說社搅,消息實(shí)體只存在于其中一個節(jié)點(diǎn)驻债,A乳规、B兩個節(jié)點(diǎn)僅有相同的元數(shù)據(jù)形葬,即隊(duì)列結(jié)構(gòu),但隊(duì)列的元數(shù)據(jù)僅保存有一份暮的,即創(chuàng)建該隊(duì)列的rabbitmq節(jié)點(diǎn)(A節(jié)點(diǎn))笙以,當(dāng)A節(jié)點(diǎn)宕機(jī),你可以去其B節(jié)點(diǎn)查看冻辩,./rabbitmqctl list_queues 發(fā)現(xiàn)該隊(duì)列已經(jīng)丟失猖腕,但聲明的exchange還存在。
當(dāng)消息進(jìn)入A節(jié)點(diǎn)的Queue中后恨闪,consumer從B節(jié)點(diǎn)拉取時(shí)倘感,RabbitMQ會臨時(shí)在A、B間進(jìn)行消息傳輸咙咽,把A中的消息實(shí)體取出并經(jīng)過B發(fā)送給consumer老玛,所以consumer應(yīng)平均連接每一個節(jié)點(diǎn),從中取消息钧敞。
該模式存在一個問題就是當(dāng)A節(jié)點(diǎn)故障后蜡豹,B節(jié)點(diǎn)無法取到A節(jié)點(diǎn)中還未消費(fèi)的消息實(shí)體。如果做了隊(duì)列持久化或消息持久化溉苛,那么得等A節(jié)點(diǎn)恢復(fù)镜廉,然后才可被消費(fèi),并且在A節(jié)點(diǎn)恢復(fù)之前其它節(jié)點(diǎn)不能再創(chuàng)建A節(jié)點(diǎn)已經(jīng)創(chuàng)建過的持久隊(duì)列愚战;如果沒有持久化的話娇唯,消息就會失丟。
這種模式更適合非持久化隊(duì)列寂玲,只有該隊(duì)列是非持久的视乐,客戶端才能重新連接到集群里的其他節(jié)點(diǎn),并重新創(chuàng)建隊(duì)列敢茁。假如該隊(duì)列是持久化的佑淀,那么唯一辦法是將故障節(jié)點(diǎn)恢復(fù)起來。
(2)鏡像模式:把需要的隊(duì)列做成鏡像隊(duì)列彰檬,存在于多個節(jié)點(diǎn)伸刃。
該模式解決了普通模式的問題,其實(shí)質(zhì)不同之處在于逢倍,消息實(shí)體會主動在鏡像節(jié)點(diǎn)間同步捧颅,而不是在consumer取數(shù)據(jù)時(shí)臨時(shí)拉取。
該模式帶來的副作用也很明顯较雕,除了降低系統(tǒng)性能外碉哑,如果鏡像隊(duì)列數(shù)量過多挚币,加之大量的消息進(jìn)入,集群內(nèi)部的網(wǎng)絡(luò)帶寬將會被這種同步通訊大大消耗掉扣典。
所以在對可靠性要求較高的場合中適用妆毕,一個隊(duì)列想做成鏡像隊(duì)列,需要先設(shè)置policy贮尖,然后客戶端創(chuàng)建隊(duì)列的時(shí)候笛粘,rabbitmq集群根據(jù)“隊(duì)列名稱”自動設(shè)置是普通集群模式或鏡像隊(duì)列。
二湿硝、RabbitMQ 基本概念
2.1 RabbitMQ 之基本概念
Message消息薪前,消息是不具名的,它由消息頭和消息體組成关斜。消息體是不透明的示括,而消息頭則由一系列的可選屬性組成,這些屬性包括routing-key(路由鍵)痢畜、priority(相對于其他消息的優(yōu)先權(quán))垛膝、delivery-mode(指出該消息可能需要持久性存儲)等。
Publisher消息的生產(chǎn)者裁着,也是一個向交換器發(fā)布消息的客戶端應(yīng)用程序繁涂。
Exchange交換器,用來接收生產(chǎn)者發(fā)送的消息并將這些消息路由給服務(wù)器中的隊(duì)列二驰。
Binding綁定扔罪,用于消息隊(duì)列和交換器之間的關(guān)聯(lián)。一個綁定就是基于路由鍵將交換器和消息隊(duì)列連接起來的路由規(guī)則桶雀,所以可以將交換器理解成一個由綁定構(gòu)成的路由表矿酵。
Queue消息隊(duì)列,用來保存消息直到發(fā)送給消費(fèi)者矗积。它是消息的容器全肮,也是消息的終點(diǎn)。一個消息可投入一個或多個隊(duì)列棘捣。消息一直在隊(duì)列里面辜腺,等待消費(fèi)者連接到這個隊(duì)列將其取走。
Connection網(wǎng)絡(luò)連接乍恐,比如一個TCP連接评疗。
Channel信道,多路復(fù)用連接中的一條獨(dú)立的雙向數(shù)據(jù)流通道茵烈。信道是建立在真實(shí)的TCP連接內(nèi)地虛擬連接百匆,AMQP 命令都是通過信道發(fā)出去的,不管是發(fā)布消息呜投、訂閱隊(duì)列還是接收消息加匈,這些動作都是通過信道完成存璃。因?yàn)閷τ诓僮飨到y(tǒng)來說建立和銷毀 TCP 都是非常昂貴的開銷,所以引入了信道的概念雕拼,以復(fù)用一條 TCP 連接纵东。
Consumer消息的消費(fèi)者,表示一個從消息隊(duì)列中取得消息的客戶端應(yīng)用程序悲没。
Virtual Host虛擬主機(jī)篮迎,表示一批交換器男图、消息隊(duì)列和相關(guān)對象示姿。虛擬主機(jī)是共享相同的身份認(rèn)證和加密環(huán)境的獨(dú)立服務(wù)器域。每個 vhost 本質(zhì)上就是一個 mini 版的 RabbitMQ 服務(wù)器逊笆,擁有自己的隊(duì)列栈戳、交換器、綁定和權(quán)限機(jī)制难裆。vhost 是 AMQP 概念的基礎(chǔ)子檀,必須在連接時(shí)指定,RabbitMQ 默認(rèn)的 vhost 是 / 乃戈。
Broker表示消息隊(duì)列服務(wù)器實(shí)體褂痰。
2.2 RabbitMQ 之AMPQ
AMQP,即Advanced Message Queuing Protocol症虑,高級消息隊(duì)列協(xié)議缩歪,是應(yīng)用層協(xié)議的一個開放標(biāo)準(zhǔn),為面向消息的中間件設(shè)計(jì)谍憔。消息中間件主要用于組件之間的解耦匪蝙,消息的發(fā)送者無需知道消息使用者的存在,反之亦然习贫。? 它可以使對應(yīng)的客戶端(client)與對應(yīng)的消息中間件(broker)進(jìn)行交互逛球。消息中間件從發(fā)布者(publisher)那里收到消息(發(fā)布消息的應(yīng)用,也稱為producer)苫昌,然后將他們轉(zhuǎn)發(fā)給消費(fèi)者(consumers颤绕,處理消息的應(yīng)用)。由于AMQP是一個網(wǎng)絡(luò)協(xié)議祟身,所以發(fā)布者告组、消費(fèi)者以及消息中間件可以部署到不同的物理機(jī)器上面。
2.3 RabbitMQ 之Exchange類型
Exchange分發(fā)消息時(shí)根據(jù)類型的不同分發(fā)策略有區(qū)別区赵,目前共四種類型:direct挖滤、fanout、topic父款、headers 溢谤。headers 匹配 AMQP 消息的 header 而不是路由鍵瞻凤,此外 headers 交換器和 direct 交換器完全一致,但性能差很多世杀,目前幾乎用不到了阀参,所以直接看另外三種類型:
(1)Direct:消息中的路由鍵(routing key)如果和 Binding 中的 binding key 一致, 交換器就將消息發(fā)到對應(yīng)的隊(duì)列中瞻坝。路由鍵與隊(duì)列名完全匹配蛛壳,如果一個隊(duì)列綁定到交換機(jī)要求路由鍵為“dog”,則只轉(zhuǎn)發(fā) routing key 標(biāo)記為“dog”的消息所刀,不會轉(zhuǎn)發(fā)“dog.puppy”衙荐,也不會轉(zhuǎn)發(fā)“dog.guard”等等。它是完全匹配浮创、單播的模式忧吟。
(2)fanout:每個發(fā)到fanout類型交換器的消息都會分到所有綁定的隊(duì)列上去。fanout 交換器不處理路由鍵斩披,只是簡單的將隊(duì)列綁定到交換器上溜族,每個發(fā)送到交換器的消息都會被轉(zhuǎn)發(fā)到與該交換器綁定的所有隊(duì)列上。很像子網(wǎng)廣播垦沉,每臺子網(wǎng)內(nèi)的主機(jī)都獲得了一份復(fù)制的消息煌抒。fanout 類型轉(zhuǎn)發(fā)消息是最快的。
(3)topic:topic交換器通過模式匹配分配消息的路由鍵屬性厕倍,將路由鍵和某個模式進(jìn)行匹配寡壮,此時(shí)隊(duì)列需要綁定到一個模式上。它將路由鍵和綁定鍵的字符串切分成單詞绑青,這些單詞之間用點(diǎn)隔開诬像。它同樣也會識別兩個通配符:符號“#”和符號“”。#匹配0個或多個單詞闸婴,匹配不多不少一個單詞坏挠。
(4)headers:headers類型的Exchange不依賴于routing key與binding key的匹配規(guī)則來路由消息,而是根據(jù)發(fā)送的消息內(nèi)容中的headers屬性進(jìn)行匹配邪乍。
在綁定Queue與Exchange時(shí)指定一組鍵值對降狠;當(dāng)消息發(fā)送到Exchange時(shí),RabbitMQ會取到該消息的headers(也是一個鍵值對的形式)庇楞,對比其中的鍵值對是否完全匹配Queue與Exchange綁定時(shí)指定的鍵值對榜配;如果完全匹配則消息會路由到該Queue,否則不會路由到該Queue吕晌。
2.4 RabbitMQ的名詞
Broker:簡單來說就是消息隊(duì)列服務(wù)器實(shí)體蛋褥。
Exchange:消息交換機(jī),它指定消息按什么規(guī)則睛驳,路由到哪個隊(duì)列烙心。
Queue:消息隊(duì)列載體膜廊,每個消息都會被投入到一個或多個隊(duì)列。
Binding:綁定淫茵,它的作用就是把exchange和queue按照路由規(guī)則綁定起來爪瓜。
Routing Key:路由關(guān)鍵字,exchange根據(jù)這個關(guān)鍵字進(jìn)行消息投遞匙瘪。
vhost:虛擬主機(jī)铆铆,一個broker里可以開設(shè)多個vhost,用作不同用戶的權(quán)限分離丹喻。
Producer:消息生產(chǎn)者薄货,就是投遞消息的程序。
Consumer:消息消費(fèi)者驻啤,就是接受消息的程序菲驴。
Channel:消息通道荐吵,在客戶端的每個連接里骑冗,可建立多個channel,每個channel代表一個會話任務(wù)先煎。
2.5 RabbitMQ消息隊(duì)列的使用過程
1贼涩、客戶端連接到消息隊(duì)列服務(wù)器,打開一個channel薯蝎。
2遥倦、客戶端聲明一個exchange,并設(shè)置相關(guān)屬性占锯。
3袒哥、客戶端聲明一個queue,并設(shè)置相關(guān)屬性消略。
4堡称、客戶端使用routing key,在exchange和queue之間建立好綁定關(guān)系艺演。
5却紧、客戶端投遞消息到exchange。
6胎撤、exchange接收到消息后晓殊,就根據(jù)消息的key和已經(jīng)設(shè)由binding,進(jìn)行消息路里伤提,將消息投遞到一個或多個隊(duì)列里
ps:通過durable參數(shù)來進(jìn)行exchang巫俺、queue、消息持久化
三肿男、RabbitMQ集群
RabbitMQ最優(yōu)秀的功能之一就是內(nèi)建集群介汹,這個功能設(shè)計(jì)的目的是允許消費(fèi)者和生產(chǎn)者在節(jié)點(diǎn)崩潰的情況下繼續(xù)運(yùn)行砚著,以及通過添加更多的節(jié)點(diǎn)來線性擴(kuò)展消息通信吞吐量。RabbitMQ 內(nèi)部利用 Erlang 提供的分布式通信框架 OTP 來滿足上述需求痴昧,使客戶端在失去一個 RabbitMQ 節(jié)點(diǎn)連接的情況下稽穆,還是能夠重新連接到集群中的任何其他節(jié)點(diǎn)繼續(xù)生產(chǎn)、消費(fèi)消息赶撰。
3.1 RabbitMQ集群中的一些概念
RabbitMQ會始終記錄以下四種類型的內(nèi)部元數(shù)據(jù):
(1)隊(duì)列元數(shù)據(jù)包括隊(duì)列名稱和它們的屬性舌镶,比如是否可持久化,是否自動刪除
(2)交換器元數(shù)據(jù)交換器名稱豪娜、類型餐胀、屬性
(3)綁定元數(shù)據(jù)內(nèi)部是一張表格記錄如何將消息路由到隊(duì)列
(4)vhost元數(shù)據(jù)為 vhost 內(nèi)部的隊(duì)列、交換器瘤载、綁定提供命名空間和安全屬性
在單一節(jié)點(diǎn)中否灾,RabbitMQ會將所有這些信息存儲在內(nèi)存中,同時(shí)將標(biāo)記為可持久化的隊(duì)列鸣奔、交換器墨技、綁定存儲到硬盤上。存到硬盤上可以確保隊(duì)列和交換器在節(jié)點(diǎn)重啟后能夠重建挎狸。而在集群模式下同樣也提供兩種選擇:存到硬盤上(獨(dú)立節(jié)點(diǎn)的默認(rèn)設(shè)置)扣汪,存在內(nèi)存中。
如果在集群中創(chuàng)建隊(duì)列锨匆,集群只會在單個節(jié)點(diǎn)而不是所有節(jié)點(diǎn)上創(chuàng)建完整的隊(duì)列信息(元數(shù)據(jù)崭别、狀態(tài)、內(nèi)容)恐锣。結(jié)果是只有隊(duì)列的所有者節(jié)點(diǎn)知道有關(guān)隊(duì)列的所有信息茅主,因此當(dāng)集群節(jié)點(diǎn)崩潰時(shí),該節(jié)點(diǎn)的隊(duì)列和綁定就消失了土榴,并且任何匹配該隊(duì)列的綁定的新消息也丟失了诀姚。還好RabbitMQ 2.6.0之后提供了鏡像隊(duì)列以避免集群節(jié)點(diǎn)故障導(dǎo)致的隊(duì)列內(nèi)容不可用。
RabbitMQ集群中可以共享 user鞭衩、vhost学搜、exchange等,所有的數(shù)據(jù)和狀態(tài)都是必須在所有節(jié)點(diǎn)上復(fù)制的论衍,例外就是上面所說的消息隊(duì)列瑞佩。RabbitMQ 節(jié)點(diǎn)可以動態(tài)的加入到集群中。
當(dāng)在集群中聲明隊(duì)列坯台、交換器炬丸、綁定的時(shí)候,這些操作會直到所有集群節(jié)點(diǎn)都成功提交元數(shù)據(jù)變更后才返回。集群中有內(nèi)存節(jié)點(diǎn)和磁盤節(jié)點(diǎn)兩種類型稠炬,內(nèi)存節(jié)點(diǎn)雖然不寫入磁盤焕阿,但是它的執(zhí)行比磁盤節(jié)點(diǎn)要好。內(nèi)存節(jié)點(diǎn)可以提供出色的性能首启,磁盤節(jié)點(diǎn)能保障配置信息在節(jié)點(diǎn)重啟后仍然可用暮屡,那集群中如何平衡這兩者呢?
RabbitMQ只要求集群中至少有一個磁盤節(jié)點(diǎn)毅桃,所有其他節(jié)點(diǎn)可以是內(nèi)存節(jié)點(diǎn)褒纲,當(dāng)節(jié)點(diǎn)加入或離開集群時(shí),它們必須要將該變更通知到至少一個磁盤節(jié)點(diǎn)钥飞。如果只有一個磁盤節(jié)點(diǎn)莺掠,剛好又是該節(jié)點(diǎn)崩潰了,那么集群可以繼續(xù)路由消息读宙,但不能創(chuàng)建隊(duì)列彻秆、創(chuàng)建交換器、創(chuàng)建綁定结闸、添加用戶唇兑、更改權(quán)限、添加或刪除集群節(jié)點(diǎn)膀估。換句話說集群中的唯一磁盤節(jié)點(diǎn)崩潰的話幔亥,集群仍然可以運(yùn)行,但直到該節(jié)點(diǎn)恢復(fù)察纯,否則無法更改任何東西。
3.2 RabbitMQ集群配置和啟動
如果是在一臺機(jī)器上同時(shí)啟動多個RabbitMQ節(jié)點(diǎn)來組建集群的話针肥,只用上面介紹的方式啟動第二饼记、第三個節(jié)點(diǎn)將會因?yàn)楣?jié)點(diǎn)名稱和端口沖突導(dǎo)致啟動失敗。所以在每次調(diào)用 rabbitmq-server 命令前慰枕,設(shè)置環(huán)境變量 RABBITMQ_NODENAME 和 RABBITMQ_NODE_PORT 來明確指定唯一的節(jié)點(diǎn)名稱和端口具则。下面的例子端口號從5672開始,每個新啟動的節(jié)點(diǎn)都加1具帮,節(jié)點(diǎn)也分別命名為test_rabbit_1博肋、test_rabbit_2、test_rabbit_3蜂厅。
啟動第1個節(jié)點(diǎn):
RABBITMQ_NODENAME=test_rabbit_1 RABBITMQ_NODE_PORT=5672?./sbin/rabbitmq-server -detached
啟動第2個節(jié)點(diǎn):
RABBITMQ_NODENAME=test_rabbit_2 RABBITMQ_NODE_PORT=5673?./sbin/rabbitmq-server -detached
啟動第2個節(jié)點(diǎn)前建議將 RabbitMQ 默認(rèn)激活的插件關(guān)掉匪凡,否則會存在使用了某個插件的端口號沖突,導(dǎo)致節(jié)點(diǎn)啟動不成功掘猿。
現(xiàn)在第2個節(jié)點(diǎn)和第1個節(jié)點(diǎn)都是獨(dú)立節(jié)點(diǎn)病游,它們并不知道其他節(jié)點(diǎn)的存在。集群中除第一個節(jié)點(diǎn)外后加入的節(jié)點(diǎn)需要獲取集群中的元數(shù)據(jù)稠通,所以要先停止 Erlang 節(jié)點(diǎn)上運(yùn)行的 RabbitMQ 應(yīng)用程序衬衬,并重置該節(jié)點(diǎn)元數(shù)據(jù)买猖,再加入并且獲取集群的元數(shù)據(jù),最后重新啟動 RabbitMQ 應(yīng)用程序滋尉。
停止第2個節(jié)點(diǎn)的應(yīng)用程序:
./sbin/rabbitmqctl -n test_rabbit_2 stop_app
重置第2個節(jié)點(diǎn)元數(shù)據(jù):
./sbin/rabbitmqctl -n test_rabbit_2 reset
第2節(jié)點(diǎn)加入第1個節(jié)點(diǎn)組成的集群:
./sbin/rabbitmqctl -n test_rabbit_2 join_cluster test_rabbit_1@localhost
啟動第2個節(jié)點(diǎn)的應(yīng)用程序
./sbin/rabbitmqctl -n test_rabbit_2 start_app
第3個節(jié)點(diǎn)的配置過程和第2個節(jié)點(diǎn)類似:
RABBITMQ_NODENAME=test_rabbit_3 RABBITMQ_NODE_PORT=5674 ./sbin/rabbitmq-server -detached./sbin/rabbitmqctl -n test_rabbit_3 stop_app./sbin/rabbitmqctl -n test_rabbit_3 reset./sbin/rabbitmqctl -n test_rabbit_3 join_cluster test_rabbit_1@localhost./sbin/rabbitmqctl -n test_rabbit_3 start_app
3.3 RabbitMQ集群運(yùn)維
停止某個指定的節(jié)點(diǎn)玉控,比如停止第2個節(jié)點(diǎn):
RABBITMQ_NODENAME=test_rabbit_2 ./sbin/rabbitmqctl stop
查看節(jié)點(diǎn)3的集群狀態(tài):
./sbin/rabbitmqctl -n test_rabbit_3 cluster_status
3.4 RabbitMQ集群元數(shù)據(jù)的同步
RabbitMQ集群會始終同步四種類型的內(nèi)部元數(shù)據(jù)(類似索引): a.隊(duì)列元數(shù)據(jù):隊(duì)列名稱和它的屬性; b.交換器元數(shù)據(jù):交換器名稱狮惜、類型和屬性奸远; c.綁定元數(shù)據(jù):一張簡單的表格展示了如何將消息路由到隊(duì)列; d.vhost元數(shù)據(jù):為vhost內(nèi)的隊(duì)列讽挟、交換器和綁定提供命名空間和安全屬性懒叛; 因此,當(dāng)用戶訪問其中任何一個RabbitMQ節(jié)點(diǎn)時(shí)耽梅,通過rabbitmqctl查詢到的queue/user/exchange/vhost等信息都是相同的薛窥。
3.5 RabbitMQ集群僅采用元數(shù)據(jù)同步的方式
我想肯定有不少同學(xué)會問,想要實(shí)現(xiàn)HA方案眼姐,那將RabbitMQ集群中的所有Queue的完整數(shù)據(jù)在所有節(jié)點(diǎn)上都保存一份不就可以了么诅迷?(可以類似MySQL的主主模式嘛)這樣子,任何一個節(jié)點(diǎn)出現(xiàn)故障或者宕機(jī)不可用時(shí)众旗,那么使用者的客戶端只要能連接至其他節(jié)點(diǎn)能夠照常完成消息的發(fā)布和訂閱嘛罢杉。 我想RabbitMQ的作者這么設(shè)計(jì)主要還是基于集群本身的性能和存儲空間上來考慮。第一贡歧,存儲空間滩租,如果每個集群節(jié)點(diǎn)都擁有所有Queue的完全數(shù)據(jù)拷貝,那么每個節(jié)點(diǎn)的存儲空間會非常大利朵,集群的消息積壓能力會非常弱(無法通過集群節(jié)點(diǎn)的擴(kuò)容提高消息積壓能力)律想;第二,性能绍弟,消息的發(fā)布者需要將消息復(fù)制到每一個集群節(jié)點(diǎn)技即,對于持久化消息,網(wǎng)絡(luò)和磁盤同步復(fù)制的開銷都會明顯增加樟遣。
3.6 RabbitMQ集群發(fā)送/訂閱消息的基本原理
場景1而叼、客戶端直接連接隊(duì)列所在節(jié)點(diǎn)
如果有一個消息生產(chǎn)者或者消息消費(fèi)者通過amqp-client的客戶端連接至節(jié)點(diǎn)1進(jìn)行消息的發(fā)布或者訂閱,那么此時(shí)的集群中的消息收發(fā)只與節(jié)點(diǎn)1相關(guān)豹悬,這個沒有任何問題葵陵;如果客戶端相連的是節(jié)點(diǎn)2或者節(jié)點(diǎn)3(隊(duì)列1數(shù)據(jù)不在該節(jié)點(diǎn)上),那么情況又會是怎么樣呢屿衅?
場景2埃难、客戶端連接的是非隊(duì)列數(shù)據(jù)所在節(jié)點(diǎn)
如果消息生產(chǎn)者所連接的是節(jié)點(diǎn)2或者節(jié)點(diǎn)3,此時(shí)隊(duì)列1的完整數(shù)據(jù)不在該兩個節(jié)點(diǎn)上,那么在發(fā)送消息過程中這兩個節(jié)點(diǎn)主要起了一個路由轉(zhuǎn)發(fā)作用涡尘,根據(jù)這兩個節(jié)點(diǎn)上的元數(shù)據(jù)(也就是上文提到的:指向queue的owner node的指針)轉(zhuǎn)發(fā)至節(jié)點(diǎn)1上忍弛,最終發(fā)送的消息還是會存儲至節(jié)點(diǎn)1的隊(duì)列1上。 同樣考抄,如果消息消費(fèi)者所連接的節(jié)點(diǎn)2或者節(jié)點(diǎn)3细疚,那這兩個節(jié)點(diǎn)也會作為路由節(jié)點(diǎn)起到轉(zhuǎn)發(fā)作用,將會從節(jié)點(diǎn)1的隊(duì)列1中拉取消息進(jìn)行消費(fèi)川梅。
四疯兼、RabbitMQ的幾種工作模式
4.1 Work模式?
一個生產(chǎn)者,多個消費(fèi)者贫途,每個消費(fèi)者獲取到的消息唯一吧彪。
1、 ?自動模式
消費(fèi)者從消息隊(duì)列獲取消息后丢早,服務(wù)端就認(rèn)為該消息已經(jīng)成功消費(fèi)姨裸。
2、 ?手動模式
消費(fèi)者從消息隊(duì)列獲取消息后怨酝,服務(wù)端并沒有標(biāo)記為成功消費(fèi)
消費(fèi)者成功消費(fèi)后需要將狀態(tài)返回到服務(wù)端
4.2 PS訂閱模式
一個生產(chǎn)者發(fā)送的消息會被多個消費(fèi)者獲取傀缩。
生產(chǎn)者:可以將消息發(fā)送到隊(duì)列或者是交換機(jī)。
消費(fèi)者:只能從隊(duì)列中獲取消息农猬。
如果消息發(fā)送到?jīng)]有隊(duì)列綁定的交換機(jī)上赡艰,那么消息將丟失。
4.3 Routing路由模式
1斤葱、 發(fā)送消息到交換機(jī)并且要指定路由key
2慷垮、 消費(fèi)者將隊(duì)列綁定到交換機(jī)時(shí)需要指定路由key
4.4 Topics?主題模式
將路由鍵和某模式進(jìn)行匹配,此時(shí)隊(duì)列需要綁定在一個模式上苦掘,“#”匹配一個詞或多個詞换帜,“*”只匹配一個詞。
4.5 RPC模式?
(RPC) Remote Procedure Call Protocol遠(yuǎn)程過程調(diào)用協(xié)議
在一個大型的公司鹤啡,系統(tǒng)由大大小小的服務(wù)構(gòu)成,不同的團(tuán)隊(duì)維護(hù)不同的代碼蹲嚣,部署在不同的機(jī)器递瑰。但是在做開發(fā)時(shí)候往往要用到其它團(tuán)隊(duì)的方法,因?yàn)橐呀?jīng)有了實(shí)現(xiàn)隙畜。但是這些服務(wù)部署不同的機(jī)器上抖部,想要調(diào)用就需要網(wǎng)絡(luò)通信,這些代碼繁瑣且復(fù)雜议惰,一不小心就會寫的很低效慎颗。RPC協(xié)議定義了規(guī)劃,其它的公司都給出了不同的實(shí)現(xiàn)。比如微軟的wcf俯萎,以及現(xiàn)在火熱的WebApi傲宜。
在RabbitMQ中RPC的實(shí)現(xiàn)也是很簡單高效的,現(xiàn)在我們的客戶端夫啊、服務(wù)端都是消息發(fā)布者與消息接收者函卒。
首先客戶端通過RPC向服務(wù)端發(fā)出請求
我這里有一堆東西需要你給我處理一下,correlation_id:這是我的請求標(biāo)識撇眯,erply_to:你處理完過后把結(jié)果返回到這個隊(duì)列中报嵌。
服務(wù)端拿到了請求,開始處理并返回
correlation_id:這是你的請求標(biāo)識 熊榛,原封不動的給你锚国。 這時(shí)候客戶端用自己的correlation_id與服務(wù)端返回的id進(jìn)行對比。是我的玄坦,就接收血筑。