天天看點

RabbitMQ基本概念

AMQP 和IM的差別:

AMQP:  

1、可以一對多廣播,也可以一對一廣播

2、生産者和消費者不知道對方是誰

IM:

1、隻能一對一廣播

2、生産者和消費者知道對方是誰

RabbitMQ:隻是消息代理

我們不生産消息,我們隻是消息的搬運工

每條消息隻會發送給一個訂閱者(一個蘿蔔一個坑)

消息的傳遞過程:

生産者==>MQ==>消費者

消息

有效載荷:需要傳輸的資料内容本身

标簽:用來告訴Rabbit消息應該投遞給誰

MQ的相關概念

交換器:用于接收生産者發送過來的消息    

隊列:用來存儲生産者發送過來的消息,供消費者消費,可以了解為裝消息的容器

綁定:用來決策交換器将消息發送到哪個隊列上

如果用乘坐火車打比方,可以這樣了解RabbitMQ

乘客是消息,火車站進站安檢口相當于交換器,負責接收乘客,并告訴乘客自己應該到哪個檢票口等候

檢票口排隊的乘客相當于隊列,乘坐同一班次列車的乘客在同一個檢票口檢票進站

乘客的手上的火車票相當于綁定(路由鍵),用來告訴乘客該坐哪一班次的列車,該從哪一個檢票口進站。

火車車廂裡的每一個座位就相當于消費者,一個座位隻能給一個乘客坐

隊列

什麼是隊列?

隊列(Queues)是你的消息(messages)的終點,可以了解成裝消息的容器。消息就一直在裡面,直到有用戶端(也就是消費者,Consumer)連接配接到這個隊列并且将其取走為止

隊列相關指令:

basic.consume:持續訂閱消息,将信道設定為接受模式。消息一到達隊列,消費者就接收消息,可以持續接收多條消息

basic.get:訂閱單條消息,接收消息後,取消訂閱。這樣做是為了讓消費者隻接收下一條消息,如果想獲得更多消息,需要再次發送basic.get。

basic.ack:消費者接收消息後,向RabbitMQ發送确認,表示已經收到消息

auto_ack:消費者在訂閱隊列是如果設定為auto_ack,表示消費者一旦接收消息後,RabbitMQ自動預設為消費者确認收到了消息。

basic.reject:消費者拒絕接收MQ發送過來的消息。RabbitMQ2.0版本後新增的指令

requeue:

true:如果requeue參數設定為true,則RabbitMQ将消息重新發送給下一位消費者

false:如果設定為false,則RabbitMQ将消息從隊列移除

queue.declare:建立隊列,如果不指定隊列名稱,則Rabbit會配置設定一個随機名稱,并在指令的響應中傳回

exclusive:如果設定為true,列隊變為私有的,即一個隊列隻有一個消費者

aotu-delete:當最後一個消費者取消訂閱後,隊列會自動移除。如果需要臨時建立一個隊列,可以結合exclusive使用。消費者斷開連接配接時,隊列自動移除

隊列工作原理

多個消費者訂閱同一隊列時,怎麼發送消息?

消費者A和B同時訂閱了seed_bin隊列

1、消息Message_A到達隊列seed_bin

2、RabbitMQ把Message_A發送給A

3、A确認接收到了消息Mesage_A

4、RabbitMQ将消息Message_A從隊列seed_bin删除

5、消息Message_B到達隊列seed_bin

6、RabbitMQ把Message_B發送給B

7、B确認接收到了消息Mesage_B

8、RabbitMQ将消息Message_B從隊列seed_bin删除

注意:

如果消費者收到一條消息後,從RabbiMQ隊列斷開了(或者說取消了訂閱),一直沒有發送确認。那麼MQ認為這條消息沒有發送,然後會重新将該消息發送給下一位消費者。這樣做的好處是如果接收消息的程式出現問題,或者有bug,導緻沒有發送确認,這樣RabbitMQ不會再給該應用發送消息。因為RabbitMQ會認為你的程式還沒有準備好接收下一條消息,這樣可以防止消息源源不斷的湧向你的應用,到導緻過載。

交換器

什麼是交換器?

交換器是伺服器接收到生産者發送過來的消息後,根據不同的規則,将消息投遞到不同的隊列的工具。這些規則被稱為路由鍵。隊列是通過路由鍵綁定到交換器的。當生産者将消息發給RabbitMQ代理伺服器時,消息将擁有一個路由鍵,Rabbit會将其與綁定的路由鍵踐行比對,如果比對則投遞到該隊列,如果比對不到任何綁定模式,則消息進入黑洞。

交換器的類型

direct:如果路由鍵比對,則直接投遞到對應的隊列

fanout:不處理路由鍵,向所有與之綁定的隊列投遞消息

topic:處理路由鍵,按模式比對,向符合規則的隊列投遞消息

headers:允許比對消息的header,而非路由鍵,除此之外,direct完全一緻,但性能差很多,基本不用了。

direct:

 處理路由鍵。需要将一個隊列綁定到交換機上,要求該消息與一個特定的路由鍵完全比對。這是一個完整的比對。如果一個隊列綁定到該交換機上要求路由鍵 “dog”,則隻有被标記為“dog”的消息才被轉發,不會轉發dog.puppy,也不會轉發dog.guard,隻會轉發dog。

fanout:

 不處理路由鍵。你隻需要簡單的将隊列綁定到交換機上。一個發送到交換機的消息都會被轉發到與該交換機綁定的所有隊列上。很像子網廣播,每台子網内的主機都獲得了一份複制的消息。Fanout交換機轉發消息是最快的。

topic:

将路由鍵和某模式進行比對。此時隊列需要綁定要一個模式上。符号“#”比對一個或多個詞,符号“*”比對不多不少一個詞。是以“audit.#”能夠比對到“audit.irs.corporate”,但是“audit.*” 隻會比對到“audit.irs”。請參考下圖

<a href="http://s3.51cto.com/wyfs02/M00/8A/5E/wKiom1gupJOiP0XsAADADnRuF3I943.png" target="_blank"></a>

虛拟主機

每一個RabbitMQ都能建立虛拟消息伺服器,我們稱之為虛拟主機(vhost)。

每一個vhost本質上是一個mini版的RabbitMQ伺服器,擁有自己的隊列、交換器、綁定。更重要的是他們擁有自己的權限機制。這使得你能夠安全的使用一個RabbitMQ伺服器來服務于衆多應用。vhost之于RabbitMQ就像虛拟機之于實體伺服器一樣。

使用者隻能在虛拟主機的粒度進行權限控制。是以,如果需要禁止A組通路B組的交換機/隊列/綁定,必須為A和B分别建立一個虛拟主機。每一個RabbitMQ伺服器都有一個預設的虛拟主機“/”。預設的賬号密碼都為guest,為了安全起見,應該改掉。

注意:在RabbitMQ上建立vhost時,整個叢集都會建立該vhost。

如何建立vhost?

1

<code>rabbitmqctl add_vhost [vhost_name]</code>

如何删除vhost?

<code>rabbitmqctl delete_vhost [vhost_name]</code>

如何檢視伺服器上運作的vhost?

<code>rabbitmqctl list_vhosts</code>

如何管理遠端的RabbitMQ節點?

<code>rabbitmqctl -n rabbit@server_name</code>

server_name可以是IP位址

持久化

預設情況下,當RabbitMQ伺服器重新開機後,那些隊列和交換器就都會消失。原因在于每個隊列和交換器的druable屬性。該屬性預設情況下為false,它決定了RabbitMQ是否需要在崩潰或者重新開機後重新建立隊列。将它設定為true,就不需要再伺服器重新開機後重新建立隊列和交換器了。

如果你以為隻需要将隊列和交換器的durable屬性設定為true,就可以讓消息幸免于重新開機就錯了,能從AMQP中恢複崩潰的消息,我們稱之為持久化。在消息釋出前,通過把它的“Delivery Mode”(投遞模式)設定為2,也就是持久的(persistent)即可。

注意:将投遞模式設定為2,僅僅表示消息被辨別為持久化的,它還必須被釋出到持久化的交換器,并投遞都持久化的隊列中才行。否則,包含持久化的隊列和交換器會在RabbitMQ重新開機後小時,而消息變成孤兒。是以,實作持久化必須:

1.    将交換機設成 durable。

2.    将隊列設成 durable。

3.    将消息的 Delivery Mode 設定成2 

交換器和隊列可以設定為durable,那綁定(Bindings)怎麼辦?我們無法在建立綁定的時候設定成durable。沒問題,如果你綁定了一個durable的隊列和一個durable的交換機,RabbitMQ會自動保留這個綁定。類似的,如果删除了某個隊列或交換機(無論是不是durable),依賴它的綁定都會自動删除。

注意兩點:

RabbitMQ 不允許你綁定一個非堅固(non-durable)的交換機和一個durable的隊列。反之亦然。要想成功必須隊列和交換機都是durable的。

一旦建立了隊列和交換機,就不能修改其标志了。例如,如果建立了一個non-durable的隊列,然後想把它改變成durable的,唯一的辦法就是删除這個隊列然後重制建立。是以,最好仔細檢查建立的标志。

RabbitMQ持久化的機制

RabbitMQ能確定持久性消息能夠在伺服器重新開機後恢複的方式是,将消息寫入磁盤上的一個持久性的日志檔案中。當釋出一條持久性消息到持久化交換器上時,Rabbit會先将消息發送到持久化日志檔案,然後再發送到持久化交換器。如果說這條消息路由到非持久化的隊列上,它會自動從持久性日志中移除,重新開機後無法恢複。

性能

對于一個需要在重新開機之後恢複的消息來說,它需要被寫入到磁盤上,這樣性能就會大打折扣。寫入磁盤要比寫入記憶體慢的不止一點點,而且會極大的減少RabbitMQ伺服器每秒可以處理的消息數。另外,持久消息在RabbitMQ内建叢集環境下工作得并不好。RabbitMQ叢集的任何一個節點上都沒有備份的拷貝,這意味着運作某一隊列的叢集節點崩潰了,在該節點恢複之前,這個隊列也就從叢集隊列中消失了。

事務/confirm模式

RabbitMQ使用事務會降低大約2~10倍的消息吞吐量,幾乎吸幹了RabbitMQ的性能。後來RabbitMQ團隊拿出了更好的加爵方案==&gt;“發送方确認模式”(confirm)。需要将RabbitMQ信道設定為confirm模式,并且一旦設定成為confirm模式後,必須通過重新建立信道來關閉該設定。

confirm模式工作機制:

一旦信道進入confirm模式,所有信道上釋出的消息都會被指派一個唯一的ID号(從1開始)。一旦消息被投遞給所有比對的的隊列後,信道會發送一個發送方确認模式給生産者(包含消息的ID),這樣生産者就知道消息被安全送到目标隊列了。如果消息和隊列是可持久化的,那麼确認消息隻會在隊列将消息寫入磁盤後才會發出。發送方确認模式的最大好處是異步的。一旦釋出了消息,生産者可以在等待确認的同時繼續發送下一條消息。當确認消息最終收到的時候,生産者應用程式的回調方法就會被觸發來處理該确認消息。如果RabbitMQ發生了内部錯誤進而導緻消息丢失,Rabbit會發送一條nack(not acknowledge,未确認)消息。就像發送确認消息那樣,隻不過這次明确說明消息已經丢失。由于沒有事務復原的概念,是以發送方确認模式更加輕量級,同時,對RabbitMQ代理伺服器的性能幾乎可以忽略不計。

本文轉自 曾哥最愛 51CTO部落格,原文連結:http://blog.51cto.com/zengestudy/1874402,如需轉載請自行聯系原作者

繼續閱讀