RabbitMQ詳解

RabbitMQ詳解

本文地址:http://www.host900.com/index.php/articles/351/

介紹RabbitMQ前篙螟,有必須先了解一下AMQP協(xié)議赫模。AMQP協(xié)議是一個(gè)高級抽象層消息通信協(xié)議潜支,RabbitMQ是AMQP協(xié)議的實(shí)現(xiàn)丐吓。它主要包括以下組件:

1. Server(broker):?接受客戶端連接,實(shí)現(xiàn)AMQP消息隊(duì)列和路由功能的進(jìn)程趟据。

2.?Virtual Host:其實(shí)是一個(gè)虛擬概念券犁,類似于權(quán)限控制組,一個(gè)Virtual Host里面可以有若干個(gè)Exchange和Queue汹碱,但是權(quán)限控制的最小粒度是Virtual Host

3.Exchange:接受生產(chǎn)者發(fā)送的消息粘衬,并根據(jù)Binding規(guī)則將消息路由給服務(wù)器中的隊(duì)列。ExchangeType決定了Exchange路由消息的行為咳促,例如稚新,在RabbitMQ中,ExchangeType有direct跪腹、Fanout和Topic三種褂删,不同類型的Exchange路由的行為是不一樣的。

4.Message Queue:消息隊(duì)列冲茸,用于存儲還未被消費(fèi)者消費(fèi)的消息屯阀。

5.Message:?由Header和Body組成,Header是由生產(chǎn)者添加的各種屬性的集合轴术,包括Message是否被持久化难衰、由哪個(gè)Message Queue接受、優(yōu)先級是多少等膳音。而Body是真正需要傳輸?shù)腁PP數(shù)據(jù)召衔。

6.Binding:Binding聯(lián)系了Exchange與Message Queue。Exchange在與多個(gè)Message Queue發(fā)生Binding后會生成一張路由表祭陷,路由表中存儲著Message Queue所需消息的限制條件即Binding Key。當(dāng)Exchange收到Message時(shí)會解析其Header得到Routing Key趣席,Exchange根據(jù)Routing Key與Exchange Type將Message路由到Message Queue兵志。Binding Key由Consumer在Binding Exchange與Message Queue時(shí)指定,而Routing Key由Producer發(fā)送Message時(shí)指定宣肚,兩者的匹配方式由Exchange Type決定想罕。

7.Connection:連接,對于RabbitMQ而言霉涨,其實(shí)就是一個(gè)位于客戶端和Broker之間的TCP連接按价。

8.Channel:信道,僅僅創(chuàng)建了客戶端到Broker之間的連接后笙瑟,客戶端還是不能發(fā)送消息的楼镐。需要為每一個(gè)Connection創(chuàng)建Channel,AMQP協(xié)議規(guī)定只有通過Channel才能執(zhí)行AMQP的命令往枷。一個(gè)Connection可以包含多個(gè)Channel框产。之所以需要Channel凄杯,是因?yàn)門CP連接的建立和釋放都是十分昂貴的,如果一個(gè)客戶端每一個(gè)線程都需要與Broker交互秉宿,如果每一個(gè)線程都建立一個(gè)TCP連接戒突,暫且不考慮TCP連接是否浪費(fèi),就算操作系統(tǒng)也無法承受每秒建立如此多的TCP連接描睦。RabbitMQ建議客戶端線程之間不要共用Channel膊存,至少要保證共用Channel的線程發(fā)送消息必須是串行的,但是建議盡量共用Connection忱叭。

9.Command:AMQP的命令膝舅,客戶端通過Command完成與AMQP服務(wù)器的交互來實(shí)現(xiàn)自身的邏輯。例如在RabbitMQ中窑多,客戶端可以通過publish命令發(fā)送消息仍稀,txSelect開啟一個(gè)事務(wù),txCommit提交一個(gè)事務(wù)埂息。

在了解了AMQP模型以后技潘,需要簡單介紹一下AMQP的協(xié)議棧,AMQP協(xié)議本身包括三層:

1.???????Modle Layer千康,位于協(xié)議最高層享幽,主要定義了一些供客戶端調(diào)用的命令,客戶端可以利用這些命令實(shí)現(xiàn)自己的業(yè)務(wù)邏輯拾弃,例如值桩,客戶端可以通過queue.declare聲明一個(gè)隊(duì)列,利用consume命令獲取一個(gè)隊(duì)列中的消息豪椿。

2.???????Session Layer奔坟,主要負(fù)責(zé)將客戶端的命令發(fā)送給服務(wù)器,在將服務(wù)器端的應(yīng)答返回給客戶端搭盾,主要為客戶端與服務(wù)器之間通信提供可靠性咳秉、同步機(jī)制和錯(cuò)誤處理。

3.???????Transport Layer鸯隅,主要傳輸二進(jìn)制數(shù)據(jù)流澜建,提供幀的處理、信道復(fù)用蝌以、錯(cuò)誤檢測和數(shù)據(jù)表示炕舵。

從AMQP協(xié)議可以看出,MessageQueue跟畅、Exchange和Binding構(gòu)成了AMQP協(xié)議的核心咽筋,下面我們就圍繞這三個(gè)主要組件 ?? 從應(yīng)用使用的角度全面的介紹如何利用Rabbit MQ構(gòu)建消息隊(duì)列以及使用過程中的注意事項(xiàng)。

1.?聲明MessageQueue

在Rabbit MQ中碍彭,無論是生產(chǎn)者發(fā)送消息還是消費(fèi)者接受消息晤硕,都首先需要聲明一個(gè)MessageQueue悼潭。這就存在一個(gè)問題,是生產(chǎn)者聲明還是消費(fèi)者聲明呢舞箍?要解決這個(gè)問題舰褪,首先需要明確:

a)消費(fèi)者是無法訂閱或者獲取不存在的MessageQueue中信息。

b)消息被Exchange接受以后疏橄,如果沒有匹配的Queue占拍,則會被丟棄。

在明白了上述兩點(diǎn)以后捎迫,就容易理解如果是消費(fèi)者去聲明Queue晃酒,就有可能會出現(xiàn)在聲明Queue之前,生產(chǎn)者已發(fā)送的消息被丟棄的隱患窄绒。如果應(yīng)用能夠通過消息重發(fā)的機(jī)制允許消息丟失贝次,則使用此方案沒有任何問題。但是如果不能接受該方案彰导,這就需要無論是生產(chǎn)者還是消費(fèi)者蛔翅,在發(fā)送或者接受消息前,都需要去嘗試建立消息隊(duì)列位谋。這里有一點(diǎn)需要明確山析,如果客戶端嘗試建立一個(gè)已經(jīng)存在的消息隊(duì)列,Rabbit MQ不會做任何事情掏父,并返回客戶端建立成功的笋轨。

如果一個(gè)消費(fèi)者在一個(gè)信道中正在監(jiān)聽某一個(gè)隊(duì)列的消息,Rabbit MQ是不允許該消費(fèi)者在同一個(gè)channel去聲明其他隊(duì)列的赊淑。Rabbit MQ中爵政,可以通過queue.declare命令聲明一個(gè)隊(duì)列,可以設(shè)置該隊(duì)列以下屬性:

a) Exclusive:排他隊(duì)列膏燃,如果一個(gè)隊(duì)列被聲明為排他隊(duì)列茂卦,該隊(duì)列僅對首次聲明它的連接可見,并在連接斷開時(shí)自動刪除组哩。這里需要注意三點(diǎn):其一,排他隊(duì)列是基于連接可見的处渣,同一連接的不同信道是可以同時(shí)訪問同一個(gè)連接創(chuàng)建的排他隊(duì)列的伶贰。其二,“首次”罐栈,如果一個(gè)連接已經(jīng)聲明了一個(gè)排他隊(duì)列黍衙,其他連接是不允許建立同名的排他隊(duì)列的,這個(gè)與普通隊(duì)列不同荠诬。其三琅翻,即使該隊(duì)列是持久化的位仁,一旦連接關(guān)閉或者客戶端退出,該排他隊(duì)列都會被自動刪除的方椎。這種隊(duì)列適用于只限于一個(gè)客戶端發(fā)送讀取消息的應(yīng)用場景聂抢。

b)?? Auto-delete:自動刪除,如果該隊(duì)列沒有任何訂閱的消費(fèi)者的話棠众,該隊(duì)列會被自動刪除琳疏。這種隊(duì)列適用于臨時(shí)隊(duì)列。

c)?? Durable:持久化闸拿,這個(gè)會在后面作為專門一個(gè)章節(jié)討論空盼。

d)??其他選項(xiàng),例如如果用戶僅僅想查詢某一個(gè)隊(duì)列是否已存在新荤,如果不存在揽趾,不想建立該隊(duì)列,仍然可以調(diào)用queue.declare苛骨,只不過需要將參數(shù)passive設(shè)為true篱瞎,傳給queue.declare,如果該隊(duì)列已存在智袭,則會返回true奔缠;如果不存在,則會返回Error吼野,但是不會創(chuàng)建新的隊(duì)列校哎。

2. 生產(chǎn)者發(fā)送消息

在AMQP模型中,Exchange是接受生產(chǎn)者消息并將消息路由到消息隊(duì)列的關(guān)鍵組件瞳步。ExchangeType和Binding決定了消息的路由規(guī)則闷哆。所以生產(chǎn)者想要發(fā)送消息,首先必須要聲明一個(gè)Exchange和該Exchange對應(yīng)的Binding单起”д可以通過 ExchangeDeclare和BindingDeclare完成。在Rabbit MQ中嘀倒,聲明一個(gè)Exchange需要三個(gè)參數(shù):ExchangeName屈留,ExchangeType和Durable。ExchangeName是該Exchange的名字测蘑,該屬性在創(chuàng)建Binding和生產(chǎn)者通過publish推送消息時(shí)需要指定灌危。ExchangeType,指Exchange的類型碳胳,在RabbitMQ中勇蝙,有三種類型的Exchange:direct ,fanout和topic挨约,不同的Exchange會表現(xiàn)出不同路由行為味混。Durable是該Exchange的持久化屬性产雹,這個(gè)會在消息持久化章節(jié)討論。聲明一個(gè)Binding需要提供一個(gè)QueueName翁锡,ExchangeName和BindingKey蔓挖。下面我們就分析一下不同的ExchangeType表現(xiàn)出的不同路由規(guī)則。

生產(chǎn)者在發(fā)送消息時(shí)盗誊,都需要指定一個(gè)RoutingKey和Exchange时甚,Exchange在接到該RoutingKey以后,會判斷該ExchangeType:

a) 如果是Direct類型哈踱,則會將消息中的RoutingKey與該Exchange關(guān)聯(lián)的所有Binding中的BindingKey進(jìn)行比較荒适,如果相等,則發(fā)送到該Binding對應(yīng)的Queue中开镣。

b)??如果是?Fanout?類型刀诬,則會將消息發(fā)送給所有與該?Exchange?定義過?Binding?的所有?Queues?中去,其實(shí)是一種廣播行為邪财。

c)如果是Topic類型陕壹,則會按照正則表達(dá)式,對RoutingKey與BindingKey進(jìn)行匹配树埠,如果匹配成功糠馆,則發(fā)送到對應(yīng)的Queue中。

3. 消費(fèi)者訂閱消息

在RabbitMQ中消費(fèi)者有2種方式獲取隊(duì)列中的消息:

a)??一種是通過basic.consume命令怎憋,訂閱某一個(gè)隊(duì)列中的消息,channel會自動在處理完上一條消息之后又碌,接收下一條消息。(同一個(gè)channel消息處理是串行的)绊袋。除非關(guān)閉channel或者取消訂閱毕匀,否則客戶端將會一直接收隊(duì)列的消息。

b)??另外一種方式是通過basic.get命令主動獲取隊(duì)列中的消息癌别,但是絕對不可以通過循環(huán)調(diào)用basic.get來代替basic.consume皂岔,這是因?yàn)閎asic.get RabbitMQ在實(shí)際執(zhí)行的時(shí)候,是首先consume某一個(gè)隊(duì)列展姐,然后檢索第一條消息躁垛,然后再取消訂閱。如果是高吞吐率的消費(fèi)者圾笨,最好還是建議使用basic.consume缤苫。

如果有多個(gè)消費(fèi)者同時(shí)訂閱同一個(gè)隊(duì)列的話,RabbitMQ是采用循環(huán)的方式分發(fā)消息的墅拭,每一條消息只能被一個(gè)訂閱者接收。例如涣狗,有隊(duì)列Queue谍婉,其中ClientA和ClientB都Consume了該隊(duì)列舒憾,MessageA到達(dá)隊(duì)列后,被分派到ClientA穗熬,ClientA回復(fù)服務(wù)器收到響應(yīng)镀迂,服務(wù)器刪除MessageA;再有一條消息MessageB抵達(dá)隊(duì)列唤蔗,服務(wù)器根據(jù)“循環(huán)推送”原則探遵,將消息會發(fā)給ClientB,然后收到ClientB的確認(rèn)后妓柜,刪除MessageB箱季;等到再下一條消息時(shí),服務(wù)器會再將消息發(fā)送給ClientA棍掐。

這里我們可以看出藏雏,消費(fèi)者再接到消息以后,都需要給服務(wù)器發(fā)送一條確認(rèn)命令作煌,這個(gè)即可以在handleDelivery里顯示的調(diào)用basic.ack實(shí)現(xiàn)掘殴,也可以在Consume某個(gè)隊(duì)列的時(shí)候,設(shè)置autoACK屬性為true實(shí)現(xiàn)粟誓。這個(gè)ACK僅僅是通知服務(wù)器可以安全的刪除該消息奏寨,而不是通知生產(chǎn)者,與RPC不同鹰服。?如果消費(fèi)者在接到消息以后還沒來得及返回ACK就斷開了連接病瞳,消息服務(wù)器會重傳該消息給下一個(gè)訂閱者,如果沒有訂閱者就會存儲該消息获诈。

既然RabbitMQ提供了ACK某一個(gè)消息的命令仍源,當(dāng)然也提供了Reject某一個(gè)消息的命令。當(dāng)客戶端發(fā)生錯(cuò)誤舔涎,調(diào)用basic.reject命令拒絕某一個(gè)消息時(shí)笼踩,可以設(shè)置一個(gè)requeue的屬性,如果為true亡嫌,則消息服務(wù)器會重傳該消息給下一個(gè)訂閱者嚎于;如果為false,則會直接刪除該消息挟冠。當(dāng)然于购,也可以通過ack,讓消息服務(wù)器直接刪除該消息并且不會重傳知染。

4.?持久化:

Rabbit MQ默認(rèn)是不持久隊(duì)列肋僧、Exchange、Binding以及隊(duì)列中的消息的,這意味著一旦消息服務(wù)器重啟嫌吠,所有已聲明的隊(duì)列止潘,Exchange,Binding以及隊(duì)列中的消息都會丟失辫诅。通過設(shè)置Exchange和MessageQueue的durable屬性為true凭戴,可以使得隊(duì)列和Exchange持久化,但是這還不能使得隊(duì)列中的消息持久化炕矮,這需要生產(chǎn)者在發(fā)送消息的時(shí)候么夫,將delivery mode設(shè)置為2,只有這3個(gè)全部設(shè)置完成后肤视,才能保證服務(wù)器重啟不會對現(xiàn)有的隊(duì)列造成影響档痪。這里需要注意的是,只有durable為true的Exchange和durable為ture的Queues才能綁定钢颂,否則在綁定時(shí)钞它,RabbitMQ都會拋錯(cuò)的。持久化會對RabbitMQ的性能造成比較大的影響殊鞭,可能會下降10倍不止遭垛。

5.?事務(wù):

對事務(wù)的支持是AMQP協(xié)議的一個(gè)重要特性。假設(shè)當(dāng)生產(chǎn)者將一個(gè)持久化消息發(fā)送給服務(wù)器時(shí)操灿,因?yàn)閏onsume命令本身沒有任何Response返回锯仪,所以即使服務(wù)器崩潰,沒有持久化該消息趾盐,生產(chǎn)者也無法獲知該消息已經(jīng)丟失庶喜。如果此時(shí)使用事務(wù),即通過txSelect()開啟一個(gè)事務(wù)救鲤,然后發(fā)送消息給服務(wù)器久窟,然后通過txCommit()提交該事務(wù),即可以保證本缠,如果txCommit()提交了斥扛,則該消息一定會持久化,如果txCommit()還未提交即服務(wù)器崩潰丹锹,則該消息不會服務(wù)器就收稀颁。當(dāng)然Rabbit MQ也提供了txRollback()命令用于回滾某一個(gè)事務(wù)。

6.?Confirm機(jī)制:

使用事務(wù)固然可以保證只有提交的事務(wù)楣黍,才會被服務(wù)器執(zhí)行匾灶。但是這樣同時(shí)也將客戶端與消息服務(wù)器同步起來,這背離了消息隊(duì)列解耦的本質(zhì)租漂。Rabbit MQ提供了一個(gè)更加輕量級的機(jī)制來保證生產(chǎn)者可以感知服務(wù)器消息是否已被路由到正確的隊(duì)列中——Confirm阶女。如果設(shè)置channel為confirm狀態(tài)颊糜,則通過該channel發(fā)送的消息都會被分配一個(gè)唯一的ID,然后一旦該消息被正確的路由到匹配的隊(duì)列中后张肾,服務(wù)器會返回給生產(chǎn)者一個(gè)Confirm芭析,該Confirm包含該消息的ID,這樣生產(chǎn)者就會知道該消息已被正確分發(fā)吞瞪。對于持久化消息,只有該消息被持久化后驾孔,才會返回Confirm芍秆。Confirm機(jī)制的最大優(yōu)點(diǎn)在于異步,生產(chǎn)者在發(fā)送消息以后翠勉,即可繼續(xù)執(zhí)行其他任務(wù)妖啥。而服務(wù)器返回Confirm后,會觸發(fā)生產(chǎn)者的回調(diào)函數(shù)对碌,生產(chǎn)者在回調(diào)函數(shù)中處理Confirm信息荆虱。如果消息服務(wù)器發(fā)生異常,導(dǎo)致該消息丟失朽们,會返回給生產(chǎn)者一個(gè)nack怀读,表示消息已經(jīng)丟失,這樣生產(chǎn)者就可以通過重發(fā)消息骑脱,保證消息不丟失菜枷。Confirm機(jī)制在性能上要比事務(wù)優(yōu)越很多。但是Confirm機(jī)制叁丧,無法進(jìn)行回滾啤誊,就是一旦服務(wù)器崩潰,生產(chǎn)者無法得到Confirm信息拥娄,生產(chǎn)者其實(shí)本身也不知道該消息吃否已經(jīng)被持久化蚊锹,只有繼續(xù)重發(fā)來保證消息不丟失,但是如果原先已經(jīng)持久化的消息稚瘾,并不會被回滾牡昆,這樣隊(duì)列中就會存在兩條相同的消息,系統(tǒng)需要支持去重孟抗。

消息持久化是?RabbitMQ?最為人津津樂道的特性之一迁杨,?RabbitMQ?能夠在付出最小的性能代價(jià)的基礎(chǔ)上實(shí)現(xiàn)消息的持久化,最大的奧秘就在于?RabbitMQ?多層消息隊(duì)列的設(shè)計(jì)上凄硼。下面铅协,本文就從?MessageQueue?的設(shè)計(jì)和消息在?MessageQueue?的生命周期兩個(gè)方面全面介紹??RabbitMQ?的消息隊(duì)列。

RabbitMQ完全實(shí)現(xiàn)了AMQP協(xié)議摊沉,類似于一個(gè)郵箱服務(wù)狐史。Exchange負(fù)責(zé)根據(jù)ExchangeType和RoutingKey將消息投遞到對應(yīng)的消息隊(duì)列中,消息隊(duì)列負(fù)責(zé)在消費(fèi)者獲取消息前暫存消息。在RabbitMQ中骏全,MessageQueue主要由兩部分組成苍柏,一個(gè)為AMQQueue,主要負(fù)責(zé)實(shí)現(xiàn)AMQP協(xié)議的邏輯功能姜贡。另外一個(gè)是用來存儲消息的BackingQueue试吁,本文重點(diǎn)關(guān)注的是BackingQueue的設(shè)計(jì)。

在RabbitMQ中BackingQueue又由5個(gè)子隊(duì)列組成:Q1楼咳、Q2熄捍、Delta、Q3和Q4母怜。RabbitMQ中的消息一旦進(jìn)入隊(duì)列余耽,不是固定不變的,它會隨著系統(tǒng)的負(fù)載在隊(duì)列中不斷流動苹熏,消息的狀態(tài)不斷發(fā)生變化碟贾。RabbitMQ中的消息一共有5種狀態(tài):

a)Alpha:消息的內(nèi)容和消息索引都保存在內(nèi)存中;

b)Beta:消息內(nèi)容保存在磁盤上轨域,消息索引保存在內(nèi)存中袱耽;

c)Gamma:消息內(nèi)容保存在磁盤上,消息索引在磁盤和內(nèi)存都有疙挺;

d)Delta:消息內(nèi)容和索引都在磁盤上扛邑;

注意:對于持久化的消息,消息內(nèi)容和消息索引都必須先保存到磁盤上铐然,才會處于上述狀態(tài)中的一種蔬崩,而Gamma狀態(tài)的消息只有持久化的消息才會有該狀態(tài)。

BackingQueue?中的?5?個(gè)子隊(duì)列中的消息狀態(tài)搀暑,?Q1?和?Q4?對應(yīng)的是?Alpha?狀態(tài)沥阳,?Q2?和?Q3?是?Beta?狀態(tài),?Delta?對應(yīng)的是?Delta?狀態(tài)自点。上述就是?RabbitMQ?的多層隊(duì)列結(jié)構(gòu)的設(shè)計(jì)桐罕,我們可以看出從?Q1?到?Q4?,基本經(jīng)歷的是由?RAM?到?DISK桂敛,再到?RAM?的設(shè)計(jì)功炮。這樣的設(shè)計(jì)的好處就是當(dāng)隊(duì)列負(fù)載很高的情況下,能夠通過將一部分消息由磁盤保存來節(jié)省內(nèi)存空間术唬,當(dāng)負(fù)載降低的時(shí)候薪伏,這部分消息又漸漸回到內(nèi)存,被消費(fèi)者獲取粗仓,使得整個(gè)隊(duì)列有很好的彈性嫁怀。下面我們就來看一下设捐,整個(gè)消息隊(duì)列的工作流程。

引起消息流動主要有兩方面的因素:其一是消費(fèi)者獲取消息塘淑;其二是由于內(nèi)存不足萝招,引起消息的換出到磁盤上(?Q1-.>Q2?、?Q2->Delta?存捺、?Q3->Delta?槐沼、?Q4->Q3?)。?RabbitMQ?在系統(tǒng)運(yùn)行時(shí)會根據(jù)消息傳輸?shù)乃俣扔?jì)算一個(gè)當(dāng)前內(nèi)存中能夠保存的最大消息數(shù)量(?Target_RAM_Count?)召噩,當(dāng)內(nèi)存中的消息數(shù)量大于該值時(shí)母赵,就會引起消息的流動。進(jìn)入隊(duì)列的消息找筝,一般會按著?Q1->Q2->Delta->Q3->Q4?的順序進(jìn)行流動赛糟,但是并不是每條消息都一定會經(jīng)歷所有的狀態(tài),這個(gè)取決于當(dāng)時(shí)系統(tǒng)的負(fù)載狀況。

當(dāng)消費(fèi)者獲取消息時(shí)买乃,首先會從?Q4?隊(duì)列中獲取消息,如果?Q4?獲取成功枢泰,則返回笨蚁,如果?Q4?為空,則嘗試從?Q3?獲取消息瓷胧;首先显拳,系統(tǒng)會判斷?Q3?隊(duì)列是否為空,如果為空搓萧,則直接返回隊(duì)列為空杂数,即此時(shí)隊(duì)列中無消息(后續(xù)會論證)。如果不為空瘸洛,則取出?Q3?的消息揍移,然后判斷此時(shí)?Q3?和?Delta?隊(duì)列的長度,如果都為空反肋,則可認(rèn)為?Q2?那伐、?Delta?、?Q3?和?Q4?全部為空?(后續(xù)說明?)?石蔗,此時(shí)將?Q1?中消息直接轉(zhuǎn)移到?Q4?中罕邀,下次直接從?Q4?中獲取消息。如果?Q3?為空养距,?Delta?不空诉探,則將?Delta?中的消息轉(zhuǎn)移到?Q3?中;如果?Q3?非空铃在,則直接下次從?Q3?中獲取消息阵具。在將?Delta?轉(zhuǎn)移到?Q3?的過程中碍遍,?RabbitMQ?是按照索引分段讀取的,首先讀取某一段阳液,直到讀到的消息非空為止怕敬,然后判斷讀取的消息個(gè)數(shù)與?Delta?中的消息個(gè)數(shù)是否相等,如果相等帘皿,則斷定此時(shí)?Delta?中已無消息东跪,則直接將?Q2?和剛讀到的消息一并放入?Q3?中。如果不相等鹰溜,則僅將此次讀到的消息轉(zhuǎn)移到Q3?中虽填。這就是消費(fèi)者引起的消息流動過程。

下面我們分析一下由于內(nèi)存不足引起的消息換出曹动。消息換出的條件是內(nèi)存中保存的消息數(shù)量?+?等待?ACK?的消息的數(shù)量?>Target_RAM_Count?斋日。當(dāng)條件觸發(fā)時(shí),系統(tǒng)首先會判斷如果當(dāng)前進(jìn)入等待?ACK?的消息的速度大于進(jìn)入隊(duì)列的消息的速度時(shí)墓陈,會先處理等待?ACK?的消息恶守。步驟基本上?Q1->Q2?或者?Q3?移動,取決于?Delta?隊(duì)列是否為空贡必。?Q4->Q3?移動兔港,?Q2?和Q3?向?Delta?移動。

最后仔拟,我們來分析一下前面遺留的兩個(gè)問題衫樊,一個(gè)是為什么?Q3?隊(duì)列為空即可認(rèn)定整個(gè)隊(duì)列為空。試想如果?Q3?為空利花,Delta?不空科侈,則在?Q3?取出最后一條消息時(shí),?Delta?上的消息就會被轉(zhuǎn)移到?Q3?上晋被,與?Q3?空矛盾兑徘。如果?Q2?不空,則在?Q3?取出最后一條消息羡洛,如果?Delta?為空時(shí)挂脑,會將?Q2?的消息并入?Q3?,與?Q3?為空矛盾欲侮。如果?Q1?不空崭闲,則在?Q3?取出最后一條消息,如果?Delta?和?Q3?均為空時(shí)威蕉,則將?Q1?的消息轉(zhuǎn)移到?Q4?中刁俭,與?Q4?為空矛盾。這也解釋了另外一個(gè)問題韧涨,即為什么?Q3?和Delta?為空牍戚,?Q2?就為空侮繁。

上述就是整個(gè)消息在?RabbitMQ?隊(duì)列中流動過程。從上述流程可以看出如孝,消息如果能夠被盡早消費(fèi)掉宪哩,就不需要經(jīng)歷持久化的過程,因?yàn)檫@樣會加系統(tǒng)的開銷第晰。如果消息被消費(fèi)的速度過慢锁孟,?RabbitMQ?通過換出內(nèi)存的方式,防止內(nèi)存溢出茁瘦。

作者:Cat Qi

出處:http://qixuejia.cnblogs.com/

本文版權(quán)歸作者和博客園共有品抽,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明甜熔,且在文章頁面明顯位置給出原文連接圆恤,否則保留追究法律責(zé)任的權(quán)利

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市腔稀,隨后出現(xiàn)的幾起案子哑了,更是在濱河造成了極大的恐慌,老刑警劉巖烧颖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異窄陡,居然都是意外死亡炕淮,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門跳夭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來涂圆,“玉大人,你說我怎么就攤上這事币叹∪笄福” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵颈抚,是天一觀的道長踩衩。 經(jīng)常有香客問我,道長贩汉,這世上最難降的妖魔是什么驱富? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮匹舞,結(jié)果婚禮上褐鸥,老公的妹妹穿的比我還像新娘。我一直安慰自己赐稽,他們只是感情好叫榕,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布浑侥。 她就那樣靜靜地躺著,像睡著了一般晰绎。 火紅的嫁衣襯著肌膚如雪寓落。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天寒匙,我揣著相機(jī)與錄音零如,去河邊找鬼。 笑死锄弱,一個(gè)胖子當(dāng)著我的面吹牛考蕾,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播会宪,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼肖卧,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了掸鹅?” 一聲冷哼從身側(cè)響起塞帐,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎巍沙,沒想到半個(gè)月后葵姥,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡句携,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年榔幸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片矮嫉。...
    茶點(diǎn)故事閱讀 40,090評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡削咆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蠢笋,到底是詐尸還是另有隱情拨齐,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布昨寞,位于F島的核電站瞻惋,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏编矾。R本人自食惡果不足惜熟史,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望窄俏。 院中可真熱鬧蹂匹,春花似錦、人聲如沸凹蜈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至履植,卻和暖如春计雌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背玫霎。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工凿滤, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人庶近。 一個(gè)月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓翁脆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親鼻种。 傳聞我的和親對象是個(gè)殘疾皇子反番,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 來源 RabbitMQ是用Erlang實(shí)現(xiàn)的一個(gè)高并發(fā)高可靠AMQP消息隊(duì)列服務(wù)器。支持消息的持久化叉钥、事務(wù)罢缸、擁塞控...
    jiangmo閱讀 10,361評論 2 34
  • RabbitMQ 即一個(gè)消息隊(duì)列,主要是用來實(shí)現(xiàn)應(yīng)用程序的異步和解耦投队,同時(shí)也能起到消息緩沖枫疆,消息分發(fā)的作用。 消息...
    極樂君閱讀 1,182評論 0 13
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理敷鸦,服務(wù)發(fā)現(xiàn)养铸,斷路器,智...
    卡卡羅2017閱讀 134,659評論 18 139
  • 為了一些初學(xué)習(xí)者更好理解我就從簡單的解釋一下Rabbitmq的原理吧?轧膘,首先你可以這樣想RabbitMq就是一個(gè)隊(duì)...
    螃蟹和駱駝先生Yvan閱讀 7,404評論 6 4
  • 很久之前就特別想去西安,一來那里是我向往的古城兔甘,那里有很深的文化底蘊(yùn)谎碍,那里會給人一種歷史的歸屬感。二來是因?yàn)槟抢镉?..
    摸風(fēng)者濤濤閱讀 123評論 0 0