RabbitMQ做爲一種AMPQ代理服務器,提供了一套嚴格的通訊方式,核心部分的通訊幾乎都使用了RPC(遠程過程調用)模式。數據庫
AMQP協議定義,當客戶端要與RabbitMQ交互時,首先要向RabbitMQ發送一個協議頭(protocol header):服務器
要徹底鏈接到RabbitMQ,會通過由三個同步RPC請求所組成請求序列,這三個RPC請求分別是啓動、調整和打開鏈接。對於應用RabbitMQ而言(不許備開發RabbitMQ Client),啓動會話這個階段並非很是重要,稍做理解就好。網絡
AMQP協議定義,信道要使用AMQP鏈接做爲互相傳輸信息的渠道,並且要將傳輸過程與其餘正在進行中的會話隔離開。一個AMQP鏈接能夠有多個信道,容許客戶端和RabbitMQ之間進行屢次會話,技術上稱之爲多路複用(multiplexing)。數據結構
不要使用過多的信道! 在傳輸過程當中,信道只是分配給客戶端和RabbitMQ之間所傳遞消息的一個整數值。但在客戶端和RabbitMQ中,會爲每一個信道設置內存結構和對象,鏈接中的信道越多,用於管理該鏈接的消息流所需的內存也就越多。異步
AMQP使用類和方法在客戶端和RabbitMQ之間建立公共語言,這些類和方法被稱爲AMQP命令(AMQP Commands)。AMQP中的類定義了一個功能範圍,每一個類都包含執行不一樣任務的方法。工具
例如:Connection.Start命令,由兩部分組成:AMQP類(Class)和方法(Method)。優化
當使用命令與RabbitMQ進行交互時,執行這些命令,和所須要的全部參數,都被封裝在一種數據結構中,而且對這個數據結構進行編碼,以便傳輸。編碼
幀由五個部分組成:spa
幀類型分爲五種:代理
能夠在rabbitmq.config配置文件中設置心跳間隔,設置爲0則表明關閉心跳檢測機制(若是你的程序在必定程度上阻塞了通訊,使得心跳檢測難以正常運做)。
若是要向RabbitMQ發送消息,則會對方法幀、內容頭幀和消息幀進行編組。
發送的第一個幀是方法幀,它攜帶了命令和執行它所需的參數(如交換器和路由鍵)。
在方法幀以後的是內容頭幀,它包含了消息屬性以及消息體大小,AMQP的幀大小是有上限的,默認爲131KB,若是消息體超過了這個上限,消息內容將被拆分紅多個消息體幀。
接着是消息幀,它攜帶了具體的消息內容。
爲了更高效的處理這些幀,方法幀和內容頭幀會被打包成二進制數據,消息幀則麼有進行任何打包或編碼。
雖然幀默認大小是131KB,但客戶端在連接過程當中能夠設置更大或更小的幀,其最大可達一個32位值。
方法幀攜帶構建RPC請求所需的類、方法以及相關參數。
這些屬性告知RabbitMQ如何路由消息。Mandatory標識則告知RabbitMQ消息必須投遞成功,不然發佈消息的過程就應該是失敗的。
一般,使用Basic.Publish RPC請求發送消息是一個單向會話。可是,若是你在發佈消息時使用了mandatory標誌,則應用程序應該監遵從RabbitMQ發送回來的Basic.Return命令。若是RabbitMQ不能知足mandatory標誌設置的要求,它將在同一個信道上發送一個Basic.Return命令到客戶端。
內容頭幀除了告知RabbitMQ該消息的大小以外,還包含消息的各類屬性。這些屬性存儲在Basic.Properties映射表中,可包含描述消息內容的數據,也可徹底是空白的。大多數客戶端會預先填充一小部分字段,好比內容類型和投遞模式。
屬性是編寫消息的強大工具,他們能夠用來在發佈者和消費則之間就消息的內容建立契約,從而容許對消息進行大量的定製操做。
消息題幀包含了實際消息數據的結構,能夠是圖片的二進制數據、序列化後的JSON、XML或字符串等等。
在將消息發佈到隊列前,有幾個與配置相關的步驟,至少須要設置交換器和隊列,而後將他們綁定到一塊兒,下面會從協議級別來看看進行這麼步驟所發生的內部過程。
協議中,建立交換器會使用Exchange.Declare命令,該命令提供了定義交換器名稱和類型的參數,以及用於消息處理的其餘元數據。
一旦命令被髮出,RabbitMQ在建立了交換器以後將發送一個Exchange.DeclareOk的方法幀做爲相應。若是處於某些緣由建立失敗了,則RabbitMQ將使用Channel.Close命令關閉發送Channel.Declare命令的信道。該響應包含一個數字編碼和文本值,用於說明Exchange.Declare失敗並關閉信道的緣由。
協議中,建立隊列會使用Queue.Declare命令,和建立交換器的過程是同樣的。
在聲明隊列時,屢次發送同一個Queue.Declare命令並不會有任何反作用。
當嘗試聲明一個與現有隊列同名的新隊列時,若是新隊列的屬性與現有隊列不同,那麼RabbitMQ將關閉發出RPC請求的通道。 要正確的處理錯誤,通常是由客戶端的實現來監聽來自RabbitMQ的Channel.Close命令,以便能作出正確響應。 某些客戶端實現可讓你返回異常,讓你的應用程序去捕獲並處理。還有的客戶端提供回調風格,經過註冊一個回調方法來處理。
協議中,綁定交換器與隊列的命令是Queue.Bind,每次只能指定一個隊列。這一步和建立交換器或建立隊列是同樣的。
協議中,當發佈消息到RabbitMQ時,多個幀封裝了發送到服務器的消息數據。
在實際的消息內容到達RabbitMQ以前,客戶端應用程序發送一個Basic.Publish方法幀,一個內容頭幀和至少一個消息體幀。
當RabbitMQ接收到一個消息的全部幀並肯定下一步操做以前,它將檢查方法幀以獲取它所須要的信息。Basic.Publish方法幀攜帶消息的交換器名稱和路由鍵。在評估這些數據時,RabbitMQ會嘗試將Basic.Publish幀中的交換器名稱與配置交換器的數據庫進行匹配。
默認狀況下,若是使用RabbitMQ配置中不存在交換器進行消息發佈,RabbitMQ將自動丟棄該消息。
若是交換器存在,可是路由不到隊列,那麼,想要確保消息成功投遞,須要在發佈時將mandatory標識設置爲true,或者使用投遞確認機制。
當RabbitMQ發現某一個交換器與Basic.Properties方法幀中的交換器名稱相匹配時,它將判斷該交換器中的綁定信息,並經過路由鍵尋找匹配的隊列。當消息與任一綁定的隊列符合匹配標準時,RabbitMQ服務器將以FIFO的順序將消息放入隊列中。
放入隊列數據結構中的並非實際消息,而是消息的引用。當RabbitMQ準備投遞消息時,它將使用這個引用來編組消息並經過網絡進行發送。這爲發佈到多個隊列的消息提供了實質性的優化。
一旦再也不須要這個消息,實際消息數據將會從RabbitMQ的內存中移除。
默認狀況下,只要沒有消費者正在監聽隊列,消息就會被存儲在隊列中。RabbitMQ能夠將這些消息保存到內存或磁盤,具體取決於Basic.Properties中指定的delivery-mode屬性。
要消費RabbitMQ隊列中的消息,消費者應用程序發出Basic.Consume命令來訂閱RabbitMQ中的隊列。服務器將返回Basic.ConsumerOk來響應。而後開始向消費者投遞消息。
若是要讓消費者中止接收消息,則能夠發送Basic.Cancel命令。這個命令是異步發出的,而RabbitMQ可能仍然在發送消息,因此消費者在接收到一個Bsaic.CancelOk響應以前,仍然能夠接收到來自RabbitMQ的消息。
消費消息時,有幾個設置可讓RabbitMQ知道你要如何接收它們。其中一個設置是Basic.Consume命令中的no_ack參數。當設置爲ture時,RabbitMQ將連續發送消息直到Basic.Cancel或者鏈接斷開。若是no_ack標記爲false,則消費者必須經過發送Basic.Ack命令來確認收到的每條消息。
當發送Basic.Ack時,消費者必須在Basic.Deliver方法幀中傳遞一個名爲delivery tag(投遞標籤)的參數。RabbitMQ使用投遞標籤和信道做爲惟一標識符來實現消息確認、拒絕等操做。