一、引言 RabbitMQ是Rabbit Message Queue的簡寫,但不能僅僅理解其為消息隊列,消息代理更合適。RabbitMQ是一個由 Erlang 語言開發的AMQP(高級消息隊列協議)的開源實現,其內部結構如下: RabbitMQ作為一個消息代理,主要和消息打交道,負責接收並轉發消息。 ...
一、引言
RabbitMQ是Rabbit Message Queue的簡寫,但不能僅僅理解其為消息隊列,消息代理更合適。RabbitMQ是一個由 Erlang 語言開發的AMQP(高級消息隊列協議)的開源實現,其內部結構如下:
RabbitMQ作為一個消息代理,主要和消息打交道,負責接收並轉發消息。RabbitMQ提供了可靠的消息機制、跟蹤機制和靈活的消息路由,支持消息集群和分散式部署。適用於排隊演算法、秒殺活動、消息分發、非同步處理、數據同步、處理耗時任務、CQRS等應用場景。
二、基礎概念
講解基礎概念之前,先來構造一個整體結構圖,以方便我們更好地去理解RabbitMQ的基本原理。
通過上面這張結構圖,能夠清晰地瞭解到Send Message到Receive Message的一個大致流程。
2.1、Queue
Queue(隊列)在RabbitMQ中的作用是存儲消息,隊列的特性是先進先出。上圖可以清晰地看到Client A和Client B是生產者,生產者生產消息最終被送到RabbitMQ的內部對象Queue中去,而消費者則是從Queue中取出數據,可以簡化表示為:
生產者Send Message,“A”被傳送到Queue中,消費者發現消息隊列Queue中有訂閱的消息,就會將這條消息A讀取出來進行一系列的業務操作。這裡是一個消費者對應一個隊列Queue,也可以多個消費者訂閱同一個隊列Queue,此時就會將Queue裡面的消息平分給其他的消費者,但是會存在一個問題就是如果每個消息的處理時間不同,就會導致某些消費者一直在忙碌中,而有的消費者處理完消息後一直處於空閑狀態。這時我們可以使用prefetchCount來限制每次發送給消費者消息的個數,詳情見下圖所示:
這裡的prefetchCount=1是指每次從Queue中發送一條消息,等消費者處理完這條消息後,Queue會再發送一條消息給消費者。
2.2、Exchange
在本節開頭的結構圖中我們留下了一個坑:消費者Client A和消費者Client B,是如何知道要發送的消息是給Queue1還是給Queue2的呢?下麵讓我們來解開這個面紗。首先要明確的一點是:生產者生產的消息並不是直接發送給消息隊列Queue的,而是要經過Exchange(交換器)將消息路由到一個或多個Queue,當然這裡還會對不符合路由規則的消息進行丟棄,這個涉及到後面要講的Exchange Type。那麼Exchange是怎樣將消息準確地推送到對應的Queue的呢?功勞最大的當屬Binding。RabbitMQ通過Binding將Exchange和Queue鏈接在一起,這樣Exchange就知道如何將消息準確地推送到Queue中去了,簡單示意圖如下所示:
生產者將消息發送給Exchange的時候,一般會產生一個Routing Key,而通過Binding鏈接Exchange和Queue的時候,一般會指定一個Binding Key。當Routing Key與Binding Key對應得上的時候,消息就會發送到對應的Queue中去。
2.3、Exchange Type
Exchange Type有4種,不同的類型有著不同的策略,也就意味著類型的不同將決定著綁定的Queue的不同。換言之,生產者發送了一個消息,Routing Key的規則是A,那麼生產者會將Routing Key=A的消息推送到Exchange中,這時候Exchange根據自己的規則去篩選生產者發來的消息。
- fanout
fanout類型的Exchange,路由規則非常簡單:它會把所有發送到該Exchange的消息,路由到所有與它綁定的Queue中。
上圖所示,生產者(P)將消息1推送到Exchange,由於Exchange Type=fanout,這時候會遵循fanout的規則將消息推送到所有與它綁定的Queue中(上圖的兩個Queue),最後給兩個消費者消費。
- direct
direct類型的Exchange,路由規則也很簡單:它會把消息路由到那些Routing Key與Binding Key完全匹配的Queue中。
當生產者(P)發送消息時Rotuing key=booking,Exchange獲取到生產者發送過來的消息後,會根據自身的規則進行匹配相應的Queue,這時發現Queue1和Queue2都符合,就會將消息傳送給這兩個隊列。如果我們以Rotuing key=create和Rotuing key=confirm發送消息時,這時消息只會被推送到Queue2隊列中,其它Routing Key的消息將會被丟棄。
- topic
如果說前面的direct規則是嚴格意義上的匹配(即Routing Key必須與Binding Key相匹配的時候才將消息傳送給Queue),那麼topic這個規則就是模糊匹配,可以通過通配符滿足一部分規則就可以傳送,它的約定是:
1)Routing Key為一個句點號“. ”分隔的字元串(我們將被句點號“. ”分隔開的每一段獨立的字元串稱為一個單詞),如“stock.usd.nyse”、“nyse.vmw”、“quick.orange.rabbit”。
2)Binding Key與Routing Key一樣也是句點號“. ”分隔的字元串。
3)Binding Key中可以存在兩種特殊字元“*”與“#”,用於做模糊匹配,其中“*”用於匹配一個單詞,“#”用於匹配多個單詞(可以是零個)。
當生產者發送消息Routing Key=F.C.E的時候,這時候只滿足Queue1,所以會被路由到Queue1中;如果Routing Key=A.C.E這時候會被同時路由到Queue1和Queue2中;如果Routing Key=A.F.B時,這時只會路由到Queue2中。
- headers
headers類型的Exchange,不依賴於Routing Key與Binding Key的匹配規則來路由消息,而是根據發送的消息內容中的headers屬性進行匹配。
在綁定Exchange與Queue時指定一組鍵值對,當消息發送到Exchange時,RabbitMQ會取到該消息的headers(也是一個鍵值對的形式),並對比其中的鍵值對是否完全匹配Exchange與Queue綁定時指定的鍵值對,如果完全匹配則消息會路由到該Queue,否則不會路由到該Queue。該類型的Exchange沒有用到過(不過也應該很有用武之地),所以不作介紹。
下麵對4種Exchange類型進行簡要的表格整理:
類型名稱 | 類型描述 |
fanout | 把所有發送到該Exchange的消息路由到所有與它綁定的Queue中 |
direct | Routing Key==Binding Key |
topic | 簡稱模糊匹配 |
headers | Exchange不依賴於Routing Key與Binding Key的匹配規則來路由消息,而是根據發送的消息內容中的headers屬性進行匹配。 |
2.4、補充說明
ConnectionFactory、Connection、Channel:都是RabbitMQ對外API中最基本的對象。
ConnectionFactory:Connection的製造工廠。
Connection:RabbitMQ的socket鏈接,它封裝了socket協議相關的邏輯。Connection建立一個TCP連接,生產者和消費者通過TCP連接到RabbitMQ Server。
Channel:
1)Channel是與RabbitMQ打交道的最重要的一個介面,我們大部分的業務操作都是通過Channel這個介面來完成的,包括定義Exchange與Queue、綁定Exchange與Queue、發佈消息等。
2)Channel虛擬連接,是建立在上面TCP連接的基礎上。數據流動都是通過Channel來進行的,為什麼不是直接在TCP連接上進行數據流動呢?是因為建立和關閉TCP連接是有代價的。頻繁地建立與關閉TCP連接對於系統的性能有很大的影響,而且TCP的連接數也有限制,這也限制了系統處理高併發的能力,而在TCP連接中建立Channel是沒有上述代價的。
參考自:
https://www.cnblogs.com/dwlsxj/p/RabbitMQ.html
https://www.cnblogs.com/sheng-jie/p/7192690.html