認識RabbitMQ交換機模型
前言
RabbitMQ是訊息佇列中介軟體(Message Queue Middleware)中一種,工作雖然有用到,但是卻沒有形成很好的整體包括,主要是一些基礎概念的認識,這裡通過閱讀《RabbitMQ實戰指南》整理筆記並進行程式碼實踐,更好地理解RabbitMQ!
本文只通過講解RabbitMQ的一些基礎概念,主要是RabbitMQ的“生產者-消費者”模型涉及到的交換器、路由鍵、繫結鍵、訊息路由規則等,下一篇會有簡單介紹RabbitMQ的運轉、RabbitMQ部署,Java程式碼實踐。
需要電子書PDF版《RabbitMQ實戰指南》(高清帶標籤)可以評論或者聯絡我
一、MQ的作用
講解RabbitMQ之前先認識下MQ作為訊息中介軟體的作用(優點),使用的時候如果不去思考為什麼用MQ,怎樣更好地才能達到它的作用的話,那都是毫無意義的使用!
1、解耦: 可以很好地遮蔽應用程式及平臺之間的特性,充當中間者,鬆散耦合應用程式及平臺,它們彼此不需要了解遠端過程呼叫RPC與網路協議的細節;
2、非同步通訊: 能提供C/S之間同步與非同步連線,在任何時刻都可以將訊息進行傳送或者儲存轉發;
3、可恢復性: 當訊息接收方宕機或網路不通的情況下,訊息轉儲於MQ中,直到網路恢復或接收方恢復再進行轉發;
4、擴充套件性: 提高訊息入佇列和處理效率是容易的,只需要另外增加處理過程即可,不需要改變程式碼,也不需要調節引數。
5、順序性: 由於大部分MQ支援佇列模式,自然也就能保證一定的資料處理順序;
6、緩衝 : MQ通過一個緩衝層來幫助任務最高效率執行,寫入MQ的處理會盡可能快速。
二、RabbitMQ的“交換機”模型
RabbitMQ整體的模型其實是一種 “生產者-消費者” 模型,傳送訊息的一方稱之為生產者,接收訊息一方稱之為消費者。中間會有交換器、佇列、Broker等概念。下圖是簡單的RabbitMQ的模型圖(截圖來自於《RabbitMQ實戰指南》,以下截圖同)
1、生產者-消費者與RabbitMQ Broker
(1)Producer:
投遞訊息的一方,建立了訊息之後釋出到RabbitMQ中, 訊息主要包括訊息體(Payload)與Label標籤 ,訊息體可以通常是業務資料,比如JSON等,Label則用來表述這條訊息,比如一個交換機名稱和一個路由鍵。
生產者把訊息交由RabbitMQ,之後會根據標籤把訊息傳送給感興趣的消費者。
(2 Consumer:
消費者,接收訊息的一方,連線到RabbitMQ伺服器,並訂閱到佇列上, 當消費者消費一條訊息時只是消費了訊息體payload,在訊息路由過程中,訊息的標籤會丟失 ,存入佇列中只有訊息體。消費者不需要知道生產者是誰。
(3)Broker:
訊息中介軟體的服務節點,一個RabbitMQ Broker可以簡單地看做一個RabbitMQ服務節或者RabbitMQ服務例項( 大多數情況下可以看做是一臺RabbitMQ的伺服器 )
由上圖可知,訊息佇列運轉過程是這樣的:
封裝好的訊息傳送(AMQP命令為Basic.publish)到Broker中,消費者訂閱並接收(Basic.Get/Basic.Consume)訊息,之後再進行業務邏輯處理(可以再開另外的程序,不需要與接收訊息同一個程序)
2、佇列
RabbitMQ中訊息都只能儲存在佇列中,當多個消費者訂閱一個佇列時,佇列中的訊息會被平均分攤(Round-Robin),也就是並不是每個消費者都能收到所有的訊息並處理。
注意以下幾點:
1) 對於生產者生產的訊息到佇列中,並不是平均分攤 。 而是通過路由鍵、繫結鍵、交換器型別三個決定訊息最終被哪個消費者消費,之後會介紹!
2) 生產者與消費者之間的連線,並不只是通過佇列那麼簡單連線 ,而是外加通過TCP連線與通道Channel,之後也會介紹
3、交換器、路由鍵、繫結
(1) 交換器(Exchange, X ): 由上圖交換機模型圖中看不到交換器這個東西,但實際上是存在的,生產者將訊息投遞到佇列,然而真實情況是: 生產者將訊息傳送到Exchange,由Exchange再路由到一個或多個佇列中;
交換器的型別有fanout、direct、topic、headers這四種類型 ,不同的型別的交換器有其獨特的匹配規則,這裡的匹配規則其實就是決定訊息最終路由到哪的佇列的關鍵,具體請往下看
(2) 路由鍵(RoutingKey ): 生產者將訊息傳送給交換器的時候,會指定RoutingKey指定路由規則 ,實際情況是需要將RoutingKey、交換器型別、繫結鍵聯合使用才能最終生效。當交換器型別與BindingKey固定情況下,通過執行RoutingKey來決定訊息流向哪裡。
(3)繫結(BindingKey):通過 繫結鍵將交換器與佇列關聯起來,這樣RabbitMQ就知道如何正確地將訊息路由到佇列, 其實繫結鍵也是一種路由鍵的一種,不過是用在繫結交換器與佇列的時候。
總結有以下三點:
(1) 生產者將訊息傳送給哪個Exchange是需要由RoutingKey決定的,生產者需要將Exchange與哪個佇列繫結時需要由BindingKey決定的 (當然還要看交換器型別,BindingKey不一定會生效,如fanout型別交換器);
(2) 生產者將訊息傳送給交換器時,需要一個RoutingKey, 當BindingKey和RoutingKey相匹配時,訊息會被路由到物件的佇列中 (當然也要看交換器型別)。
(3) BindingKey其實也屬於路由鍵的一種 ,在使用邦定的時候,需要的路由鍵是BingdingKey,在傳送訊息的時,需要的路由鍵是RoutingKey
4、交換器型別
為什麼非要介紹交換器型別呢?上文中也提到過交換器型別關係到具體的訊息路由途徑,處路由鍵、繫結鍵之外的還需要關注交換器的型別。不同的交換器會有不同的匹配規則。
RabbitMQ常用的交換器型別有fanout、direct、topic、headers這四種類型
(1) fanout : 它會把所有的交換器上的訊息路由到所有與該交換器邦定的佇列中,不需要BindingKey生效
(2) direct :它會把 訊息路由到BindingKey與RoutingKey完全匹配的佇列中 。比如在傳送訊息的時候,設定Label中RoutingKey為warning,則訊息會路由到Queue1與Queue2上(請看下圖)。
(3) topic :是direct上的擴充套件, 同樣是利用RoutingKey與BindingKey相匹配,但是匹配規則不一樣,支援模糊匹配 。 有如下的規則
-
-
-
-
- RoutingKey為一個點號“.”分隔的字串,每個被隔開的獨立字串即為一個單詞,是匹配的單位;
- BindingKey和RoutingKey一樣,也是"."分割的字串;
- 但不同的是BindingKey,可以用“#”,“*”進行類似於佔位符的模糊匹配,“#”表示一個單詞,"*"表示多個單詞(也可以是零個)
-
-
-
比如:
RoutingKey為com.hidden.client的訊息只會到佇列Queue2中:因為只有Queue2的BindingKey=*.*.client匹配com.hidden.client
RoutingKey為com.rabbitmq.client的訊息會到佇列Queue1-2中: 因為Queue1的BindingKey=*.rabbitmq.*.匹配com.rabbitmq.client,Queue2的BindingKey=*.*.client匹配com.rabbitmq.client
RoutingKey為java.rabbitmq.demo的訊息只會到佇列Queue1中:因為只有Queue1的BindingKey=*.rabbitmq.*.匹配java.rabbitmq.demo
RoutingKey為java.util.concurrent的訊息會被丟棄或者返回給生產者(需要設定)
(4) headers :依賴傳送訊息內容中的hearders屬性進行匹配,在繫結佇列和交換器時指定一組鍵值對,這裡的也就是headers,當傳送訊息到交換器時,RabbitMQ會獲取到該訊息的headers,通過比較會路由到相關佇列中,這種交換器效能會很差,一般不會使用。
以上內容總結起來只是介紹了,RabbitMQ的從生產者產生訊息到消費者消費訊息過程中涉及到的概念。還未介紹具體的RabbitMQ是如何運轉的,比如生產者是怎樣建立建立的,消費者又是怎樣讀取訊息的。這將是下一篇主要介紹的。