RabbitMQ詳解

RabbitMQ詳解

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

介紹RabbitMQ前,有必須先了解一下AMQP協(xié)議。AMQP協(xié)議是一個(gè)高級(jí)抽象層消息通信協(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ì)列,用于存儲(chǔ)還未被消費(fèi)者消費(fèi)的消息。

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

6.Binding:Binding聯(lián)系了Exchange與Message Queue。Exchange在與多個(gè)Message Queue發(fā)生Binding后會(huì)生成一張路由表,路由表中存儲(chǔ)著Message Queue所需消息的限制條件即Binding Key。當(dāng)Exchange收到Message時(shí)會(huì)解析其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:連接,對(duì)于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ò)誤檢測(cè)和數(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,則會(huì)被丟棄。

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

如果一個(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ì)列僅對(duì)首次聲明它的連接可見,并在連接斷開時(shí)自動(dòng)刪除。這里需要注意三點(diǎn):其一,排他隊(duì)列是基于連接可見的,同一連接的不同信道是可以同時(shí)訪問同一個(gè)連接創(chuàng)建的排他隊(duì)列的。其二,“首次”,如果一個(gè)連接已經(jīng)聲明了一個(gè)排他隊(duì)列,其他連接是不允許建立同名的排他隊(duì)列的,這個(gè)與普通隊(duì)列不同。其三,即使該隊(duì)列是持久化的,一旦連接關(guān)閉或者客戶端退出,該排他隊(duì)列都會(huì)被自動(dòng)刪除的。這種隊(duì)列適用于只限于一個(gè)客戶端發(fā)送讀取消息的應(yīng)用場景。

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

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

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

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

在AMQP模型中,Exchange是接受生產(chǎn)者消息并將消息路由到消息隊(duì)列的關(guān)鍵組件。ExchangeType和Binding決定了消息的路由規(guī)則。所以生產(chǎn)者想要發(fā)送消息,首先必須要聲明一個(gè)Exchange和該Exchange對(duì)應(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會(huì)表現(xiàn)出不同路由行為。Durable是該Exchange的持久化屬性,這個(gè)會(huì)在消息持久化章節(jié)討論。聲明一個(gè)Binding需要提供一個(gè)QueueName,ExchangeName和BindingKey。下面我們就分析一下不同的ExchangeType表現(xiàn)出的不同路由規(guī)則。

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

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

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

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

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

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

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

b)??另外一種方式是通過basic.get命令主動(dòng)獲取隊(duì)列中的消息,但是絕對(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)推送”原則,將消息會(huì)發(fā)給ClientB,然后收到ClientB的確認(rèn)后,刪除MessageB;等到再下一條消息時(shí),服務(wù)器會(huì)再將消息發(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ù)器會(huì)重傳該消息給下一個(gè)訂閱者,如果沒有訂閱者就會(huì)存儲(chǔ)該消息。

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

4.?持久化:

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

5.?事務(wù):

對(duì)事務(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()提交了,則該消息一定會(huì)持久化,如果txCommit()還未提交即服務(wù)器崩潰,則該消息不會(huì)服務(wù)器就收。當(dāng)然Rabbit MQ也提供了txRollback()命令用于回滾某一個(gè)事務(wù)。

6.?Confirm機(jī)制:

使用事務(wù)固然可以保證只有提交的事務(wù),才會(huì)被服務(wù)器執(zhí)行。但是這樣同時(shí)也將客戶端與消息服務(wù)器同步起來,這背離了消息隊(duì)列解耦的本質(zhì)。Rabbit MQ提供了一個(gè)更加輕量級(jí)的機(jī)制來保證生產(chǎn)者可以感知服務(wù)器消息是否已被路由到正確的隊(duì)列中——Confirm。如果設(shè)置channel為confirm狀態(tài),則通過該channel發(fā)送的消息都會(huì)被分配一個(gè)唯一的ID,然后一旦該消息被正確的路由到匹配的隊(duì)列中后,服務(wù)器會(huì)返回給生產(chǎn)者一個(gè)Confirm,該Confirm包含該消息的ID,這樣生產(chǎn)者就會(huì)知道該消息已被正確分發(fā)。對(duì)于持久化消息,只有該消息被持久化后,才會(huì)返回Confirm。Confirm機(jī)制的最大優(yōu)點(diǎn)在于異步,生產(chǎn)者在發(fā)送消息以后,即可繼續(xù)執(zhí)行其他任務(wù)。而服務(wù)器返回Confirm后,會(huì)觸發(fā)生產(chǎn)者的回調(diào)函數(shù),生產(chǎn)者在回調(diào)函數(shù)中處理Confirm信息。如果消息服務(wù)器發(fā)生異常,導(dǎo)致該消息丟失,會(huì)返回給生產(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)持久化的消息,并不會(huì)被回滾,這樣隊(duì)列中就會(huì)存在兩條相同的消息,系統(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將消息投遞到對(duì)應(yīng)的消息隊(duì)列中,消息隊(duì)列負(fù)責(zé)在消費(fèi)者獲取消息前暫存消息。在RabbitMQ中,MessageQueue主要由兩部分組成,一個(gè)為AMQQueue,主要負(fù)責(zé)實(shí)現(xiàn)AMQP協(xié)議的邏輯功能。另外一個(gè)是用來存儲(chǔ)消息的BackingQueue,本文重點(diǎn)關(guān)注的是BackingQueue的設(shè)計(jì)。

在RabbitMQ中BackingQueue又由5個(gè)子隊(duì)列組成:Q1、Q2、Delta、Q3和Q4。RabbitMQ中的消息一旦進(jìn)入隊(duì)列,不是固定不變的,它會(huì)隨著系統(tǒng)的負(fù)載在隊(duì)列中不斷流動(dòng),消息的狀態(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)容和索引都在磁盤上;

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

BackingQueue?中的?5?個(gè)子隊(duì)列中的消息狀態(tài),?Q1?和?Q4?對(duì)應(yīng)的是?Alpha?狀態(tài),?Q2?和?Q3?是?Beta?狀態(tài),?Delta?對(duì)應(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ì)列的工作流程。

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

當(dāng)消費(fèi)者獲取消息時(shí),首先會(huì)從?Q4?隊(duì)列中獲取消息,如果?Q4?獲取成功,則返回,如果?Q4?為空,則嘗試從?Q3?獲取消息;首先,系統(tǒng)會(huì)判斷?Q3?隊(duì)列是否為空,如果為空,則直接返回隊(duì)列為空,即此時(shí)隊(duì)列中無消息(后續(xù)會(huì)論證)。如果不為空,則取出?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)者引起的消息流動(dòng)過程。

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

最后,我們來分析一下前面遺留的兩個(gè)問題,一個(gè)是為什么?Q3?隊(duì)列為空即可認(rèn)定整個(gè)隊(duì)列為空。試想如果?Q3?為空,Delta?不空,則在?Q3?取出最后一條消息時(shí),?Delta?上的消息就會(huì)被轉(zhuǎn)移到?Q3?上,與?Q3?空矛盾。如果?Q2?不空,則在?Q3?取出最后一條消息,如果?Delta?為空時(shí),會(huì)將?Q2?的消息并入?Q3?,與?Q3?為空矛盾。如果?Q1?不空,則在?Q3?取出最后一條消息,如果?Delta?和?Q3?均為空時(shí),則將?Q1?的消息轉(zhuǎn)移到?Q4?中,與?Q4?為空矛盾。這也解釋了另外一個(gè)問題,即為什么?Q3?和Delta?為空,?Q2?就為空。

上述就是整個(gè)消息在?RabbitMQ?隊(duì)列中流動(dòng)過程。從上述流程可以看出,消息如果能夠被盡早消費(fèi)掉,就不需要經(jīng)歷持久化的過程,因?yàn)檫@樣會(huì)加系統(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)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容