生產者發送消息的過程
(1)生產者連接到RabbitMQ Broker建立一個連接(Connection),開啓一個信道(Channel)
(2)生產者聲明一個交換器,並設置相關屬性,比如交換機類型、是否持久化等
(3)生產者聲明一個隊列並設置相關屬性,比如是否排他、是否持久化、是否自動刪除等
(4)生產者通過路由鍵將交換器和隊列綁定起來
(5)生產者發送消息至RabbitMQ Broker,其中包含路由鍵、交換器等信息
(6)相應的交換器根據接收到的路由鍵查找相匹配的隊列
(7)如果找到,則將從生產者發送過來的消息存入相應的隊列中。
(8)如果沒有找到,則根據生產者配置的屬性選擇丟棄還是回退給生產者
(9)關閉信道。
(10)關閉連接。
消費者接受消息的過程
(1)消費者連接到RabbitMQ Broker,建立一個連接(Connection),開啓一個信道(Channel)。
(2)消費者向RabbitMQ Broker請求消費響應隊列中的消息,可能會設置相應的回調函數,以及做一些準備工作。
(3)等待RabbitMQ Broker迴應並投遞相應隊列中的消息,消費者接受消息。
(4)消費者確認(ack)接收到的消息。
(5)RabbitMQ從隊列中刪除相應已經被確認的消息。
(6)關閉信道。
(7)關閉連接。
什麼是信道?
信道是建立在Connection之上的虛擬連接,RabbitMQ處理的每條AMQP指令都是通過信道完成的。
爲什麼引入信道?
建立和銷燬TCP連接是非常昂貴的開銷,RabbitMQ採用類似NIO(Non-blockingI/O)的做法,選擇TCP連接複用,不僅可以減少性能開銷,同時也便於管理。
exchangeDeclare方法詳解
exchange:交換器的名稱
type:交換器的類型,常見的如fanout、direct、topic。
fanout不處理routingKey;
direct處理routingKey,完全匹配;
topic將routingKey和某模式匹配;
durable:設置是否持久化。持久化可以將交換器存盤,在服務器重啓的時候不會丟失相關信息。
autoDelete:設置是否自動刪除。自動刪除的前提是至少有一個隊裏或者交換器與這個交換器綁定,之後所有與這個交換器綁定的隊列或者交換器都與此解綁。
注意不能錯誤地把這個參數理解爲:“當與此交換器鏈連接的客戶端都斷開時,RabbitMQ會自動刪除本交換器”
internal:設置是否是內置的。內置的交換器,客戶端程序無法直接發送消息到這個交換器,只能通過交換器路由到交換器這種方式。
argument:其他一些結構化參數,比如alternate-exchange
queueDeclare方法詳解
queue:隊列的名稱
durable:設置是否持久化。
exclusive:設置是否排他。如果一個隊列被聲明爲排他隊列,該隊列僅對首次聲明它的連接可見,並在連接斷開時自動刪除。這裏需要注意三點:排他隊列是基於連接(Connection)可見的,同一個連接的不同信道(Channel)是可以同時訪問同一創建的排他隊列。“首次”是指如果一個連接已經聲明瞭一個排他隊列,其他連接是不允許建立同名的排他隊列的,這個與普通隊列不同。即使該隊列是持久化的,一旦連接關閉或者客戶端退出,該排他隊列都會自動刪除,這種隊列適用於一個客戶端同時發送或讀取消息的應用場景
autoDelete:設置是否自動刪除。爲true則設置隊列爲自動刪除。自動刪除的前提是:
至少有一個消費者連接到這個隊列,之後所有與這個隊列連接的消費者都斷開時,纔會自動刪除。不能把這個參數錯誤地理解爲:"當連接到此隊列的所有客戶端斷開時,這個隊列自動刪除",因爲生產者客戶端創建這個隊列,或者沒有消費者客戶端與這個隊列連接時,都不會自動刪除這個隊列。
arguments:設置隊列的其他一些參數,如x-message-ttl、x-expires、x-max-length、x-max-length-bytes、x-dead-letter-exchange、x-dead-letter-routing-key,x-max-priority等。
queueBind方法詳解
queue:隊列名稱:
exchange:交換器的名稱:
routingKey:用來綁定隊列和交換器的路由鍵;
argument:定義綁定的一些參數。
channel.basicQos方法
允許限制信道上的消費者所能保持的最大未確認消息的數量
basicPublish發送消息
exchange:交換器的名稱,指明消息需要發送到哪個交換器中。如果設置爲空字符串,則消息會被髮送到RabbitMQ默認的交換器中。
routingKey:路由鍵,交換器根據路由鍵將消息存儲到相應的隊列之中。
props:消息的基本屬性集,其包含14個屬性成員,分別有contentType、contentEncoding、headers(Map<StringObject>)、deliveryMode、priority、correlationId、replyTo、expiration、messageId、timestamp、type、userId、appId、clusterId。其中常用的幾種都在上面的示例中進行了演示。
byte[] body:消息體(payload),真正需要發送的消息
mandatory和immediate的詳細內容請參考4.1
消費消息
RabbitMQ的消息模式分兩種:推(Push)模式和拉(Pull)模式。推模式採用Basic.Consume進行消費,而拉模式則調用Basic.Get進行消費
在推模式中,可以通過持續訂閱的方式來消費消息,使用到的相關類有:Consumer、DefaultConsumer
basicConsume方法
queue:隊列的名稱
autoAck:設置是否自動確認。
consumerTag:消費者標籤,用來區分多個消費者。
noLocal:設置爲true表示不能將同一個Connection中生產者發送的消息傳遞給這個Connection中的消費者。
exclusive:設置是否排他
arguments:設置消費者的其他參數
callback:設置消費者的回調函數。用來處理RabbitMQ推送過來的消息,比如DefaultConsumer,使用時需要客戶端重寫其中的方法。
拉模式
channel.basicGet
消費端的確認與拒絕
autoAck等於true時,RabbitMQ會自動把發送出去的消息置爲確認,然後從內存(或者磁盤)中刪除,而不管消費者是否真正地消費了這些消息。而爲false,消費者就有足夠的時間處理消息,不用擔心處理消息過程中消費者進程掛掉後消息丟失的問題,因爲RabbitMQ會一直等待持有消息直到消費者顯式調用Basic.Ack命令爲止
basicAck(envelope.getDeliveryTag(),false);告訴消息服務器來刪除消息
basicReject消息拒絕
deliveryTag:可以看作消息的編號,64位長整型
requeue:true,則RabbitMQ會重新存入隊列,false,則RabbitMQ會立即把消息從隊列中移除
mandatory和immediate是channel.basicPublish方法中的兩個參數,他們都有當消息傳遞過程中不可達目的地時將消息返回給生產者的功能。
mandatory:true,交換器無法根據自身的類型和路由鍵找到一個符合條件的隊列,那麼RabbitMQ會調用Basic.Return命令將消息返回給生產者。false,出現上述情形,則消息直接被丟棄。
immediate(3.0版本已去掉):true,如果交換器在將消息路由到隊列時發現隊列上並不存在任何消費者,那麼這條消息將不會存入隊列中。當與路由鍵匹配的所有隊列都沒有消費者時,該消息會通過Basic.Return返回至生產者
延遲隊列
DLX和相應的死信隊列:當相應的消息過期時,就會轉存到相應的死信隊列(即延遲隊列)中,這樣消費者根據業務自身的情況,分別選擇不同延遲登記的延遲隊列進行消費
vhost
每一個RabbitMQ服務器都能創建虛擬的消息服務器,我們稱之爲vhost虛擬主機,每個vhost本質上是一個獨立的小型RabbitMQ服務器,擁有自己獨立的隊列、交換器及綁定關係等,並且它擁有自己獨立的權限。
恢復機制
MQ掛了,客戶端會隔一段時間重連
隊列刪除了,客戶端會重新建一個