rabbitmq入門知識整理


微信公衆號:跟着老萬學java
關注可瞭解更多的開發技巧。問題或建議,請公衆號留言;java

什麼叫消息隊列

消息(Message)是指在應用間傳送的數據。消息能夠很是簡單,好比只包含文本字符串,也能夠更復雜,可能包含嵌入對象。
消息隊列(Message Queue)是一種應用間的通訊方式,消息發送後能夠當即返回,由消息系統來確保消息的可靠傳遞。消息發佈者只管把消息發佈到 MQ 中而不用管誰來取,消息使用者只管從 MQ 中取消息而不論是誰發佈的。這樣發佈者和使用者都不用知道對方的存在,解除了上下游調用的依賴關係,實現異步和解耦。服務器

消息隊列的做用

一、異步
二、解耦
三、削峯
四、廣播訂閱
五、RPC調用
六、順序消費
七、分佈式事務支持微信

RabbitMQ說明

RabbitMQ的官網是http://www.rabbitmq.com網絡

RabbitMQ 是一個由 Erlang 語言開發的 AMQP 的開源實現。
AMQP :Advanced Message Queue,高級消息隊列協議。它是應用層協議的一個開放標準,爲面向消息的中間件設計,基於此協議的客戶端與消息中間件可傳遞消息,並不受產品、開發語言等條件的限制。app

RabbitMQ 即一個消息隊列,主要是用來實現應用程序的異步和解耦,同時也能起到消息緩衝,消息分發的做用。異步

中間件最標準的用法是生產者生產消息傳送到隊列,消費者從隊列中拿取消息並處理,生產者不用關心是誰來消費,消費者不用關心誰在生產消息,從而達到解耦的目的。在分佈式的系統中,消息隊列也會被用在不少其它的方面,好比:分佈式事務的支持,RPC的調用等等。分佈式

RabbitMQ 特色

RabbitMQ 最初起源於金融系統,用於在分佈式系統中存儲轉發消息,在易用性、擴展性、高可用性等方面表現不俗。具體特色包括:
可靠性(Reliability)
RabbitMQ 使用一些機制來保證可靠性,如持久化、傳輸確認、發佈確認。
靈活的路由(Flexible Routing)
在消息進入隊列以前,經過 Exchange 來路由消息的。對於典型的路由功能,RabbitMQ 已經提供了一些內置的 Exchange 來實現。針對更復雜的路由功能,能夠將多個 Exchange 綁定在一塊兒,也經過插件機制實現本身的 Exchange 。
消息集羣(Clustering)
多個 RabbitMQ 服務器能夠組成一個集羣,造成一個邏輯 Broker 。
雖然支持集羣,可是並不支持消息分片。這點是和kafka集羣最大的區別
高可用(Highly Available Queues)
隊列能夠在集羣中的機器上進行鏡像,使得在部分節點出問題的狀況下隊列仍然可用。
多種協議(Multi-protocol)
RabbitMQ 支持多種消息隊列協議,好比 STOMP、MQTT 等等。
多語言客戶端(Many Clients)
RabbitMQ 幾乎支持全部經常使用語言,好比 Java、.NET、Ruby 等等。
管理界面(Management UI)
RabbitMQ 提供了一個易用的用戶界面,使得用戶能夠監控和管理消息 Broker 的許多方面。
跟蹤機制(Tracing)
若是消息異常,RabbitMQ 提供了消息跟蹤機制,使用者能夠找出發生了什麼。
插件機制(Plugin System)
RabbitMQ 提供了許多插件,來從多方面進行擴展,也能夠編寫本身的插件。函數

RabbitMQ 基本概念

上面只是最簡單抽象的描述,具體到 RabbitMQ 則有更詳細的概念須要解釋。上面介紹過 RabbitMQ 是 AMQP 協議的一個開源實現,因此其內部實際上也是 AMQP 中的基本概念:
性能


一般咱們談到隊列服務, 會有三個概念: 發消息者、隊列、收消息者,RabbitMQ 在這個基本概念之上, 多作了一層抽象, 在發消息者和 隊列之間, 加入了交換器 (Exchange). 這樣發消息者和隊列就沒有直接聯繫, 轉而變成發消息者把消息給交換器, 交換器根據調度策略再把消息發給隊列。

Messageui

消息,由消息頭和消息體組成。消息體是不透明的,而消息頭則由一系列的可選屬性組成,這些屬性包括routing-key(路由鍵)、priority(相對於其餘消息的優先權)、delivery-mode(指出該消息可能須要持久性存儲)等。

Publisher
消息的生產者,也是一個向交換器發佈消息的客戶端應用程序。

Exchange
交換器,用來接收生產者發送的消息並將這些消息路由給服務器中的隊列。

Binding
綁定,用於消息隊列和交換器之間的關聯。一個綁定就是基於路由鍵將交換器和消息隊列鏈接起來的路由規則,因此能夠將交換器理解成一個由綁定構成的路由表。

Queue
消息隊列,用來保存消息直到發送給消費者。它是消息的容器,也是消息的終點。一個消息可投入一個或多個隊列。消息一直在隊列裏面,等待消費者鏈接到這個隊列將其取走。

Connection
網絡鏈接,好比一個TCP鏈接。

Channel
信道,多路複用鏈接中的一條獨立的雙向數據流通道。信道是創建在真實的TCP鏈接內虛擬鏈接,AMQP 命令都是經過信道發出去的,不論是發佈消息、訂閱隊列仍是接收消息,這些動做都是經過信道完成。由於對於操做系統來講創建和銷燬 TCP 都是很是昂貴的開銷,因此引入了信道的概念,以複用一條 TCP 鏈接。

Consumer
消息的消費者,表示一個從消息隊列中取得消息的客戶端應用程序。

Virtual Host
虛擬主機,表示一批交換器、消息隊列和相關對象。虛擬主機是共享相同的身份認證和加密環境的獨立服務器域。每一個 vhost 本質上就是一個 mini 版的 RabbitMQ 服務器,擁有本身的隊列、交換器、綁定和權限機制。vhost 是 AMQP 概念的基礎,必須在鏈接時指定,RabbitMQ 默認的 vhost 是 / 。

爲何須要多個虛擬主機呢?
很簡單,RabbitMQ當中,用戶只能在虛擬主機的粒度進行權限控制。所以,若是須要禁止A組訪問B組的交換機/隊列/綁定,必須爲A和B分別建立一個虛擬主機。
簡單的來講,就是一個分組的概念。每一個用戶操做本身權限下的虛擬主機,相互之間互不影響。

Broker
表示消息隊列服務器實體。

重點說明一下

  1. RabbitMQ的消息發送不是面向隊列的,而是面向交換器Exchange的,交換器根據接收消息時指定的路由鍵Routing Key和交換器自身的類型以及和隊列之間創建綁定關係使用的Binding Key來決定消息發送到哪些具體的隊列中。

  2. 注意區分Routing Key和Binding Key的做用和使用場景的區別,Routing Key是生產者發送消息時指定的,用來肯定路由規則;Binding Key是交換器和隊列綁定時用到的。

核心流程

生產者發送消息流程

  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. 關閉鏈接

簡單代碼

四種路由

Exchange分發消息時根據類型的不一樣分發策略有區別,目前經常使用的四種類型:
direct、fanout、topic、headers 。
headers 匹配 AMQP 消息的 header 而不是路由鍵,此外 headers 交換器和 direct 交換器徹底一致,但性能差不少,目前幾乎用不到了,因此直接看另外三種類型:

direct
direct類型的Exchange路由規則也很簡單,它會把消息路由到那些binding key與routing key徹底匹配的Queue中。


以上圖的配置爲例,咱們以routingKey=」error」發送消息到Exchange,則消息會路由到Queue1(amqp.gen-S9b…,這是由RabbitMQ自動生成的Queue名稱)和Queue2(amqp.gen-Agl…); 若是咱們以routingKey=」info」或routingKey=」warning」來發送消息,則消息只會路由到Queue2。 若是咱們以其餘routingKey發送消息,則消息不會路由到這兩個Queue中。

topic

前面講到direct類型的Exchange路由規則是徹底匹配binding key與routing key,但這種嚴格的匹配方式在不少狀況下不能知足實際業務需求。topic類型的Exchange在匹配規則上進行了擴展,它與direct類型的Exchage類似,也是將消息路由到binding key與routing key相匹配的Queue中,但這裏的匹配規則有些不一樣,它約定:
routing key爲一個句點號「.」分隔的字符串(咱們將被句點號「. 」分隔開的每一段獨立的字符串稱爲一個單詞),如「stock.usd.nyse」、「nyse.vmw」、「quick.orange.rabbit」 binding key與routing key同樣也是句點號「. 」分隔的字符串
binding key中能夠存在兩種特殊字符「」與「#」,用於作模糊匹配,其中「」用於匹配一個單詞,「#」用於匹配多個單詞(能夠是零個)

以上圖中的配置爲例,routingKey=」quick.orange.rabbit」的消息會同時路由到Q1與Q2,routingKey=」lazy.orange.fox」的消息會路由到Q1,routingKey=」lazy.brown.fox」的消息會路由到Q2,routingKey=」lazy.pink.rabbit」的消息會路由到Q2(只會投遞給Q2一次,雖然這個routingKey與Q2的兩個bindingKey都匹配);routingKey=」quick.brown.fox」、routingKey=」orange」、routingKey=」quick.orange.male.rabbit」的消息將會被丟棄,由於它們沒有匹配任何bindingKey

fanout
fanout類型的Exchange路由規則很是簡單,它會把全部發送到該Exchange的消息路由到全部與它綁定的Queue中。


上圖中,生產者(P)發送到Exchange(X)的全部消息都會路由到圖中的兩個Queue,並最終被兩個消費者(C1與C2)消費。
fanout路由下會忽略binding key與routing key的匹配關係。

headers

headers類型的Exchange不依賴於routing key與binding key的匹配規則來路由消息,而是根據發送的消息內容中的headers屬性進行匹配。
在綁定Queue與Exchange時指定一組鍵值對;當消息發送到Exchange時,RabbitMQ會取到該消息的headers(也是一個鍵值對的形式),對比其中的鍵值對是否徹底匹配Queue與Exchange綁定時指定的鍵值對;若是徹底匹配則消息會路由到該Queue,不然不會路由到該Queue。
該類型的Exchange沒有用到過(不過也應該頗有用武之地),因此不作介紹。

RPC調用

MQ自己是基於異步的消息處理,前面的示例中全部的生產者(P)將消息發送到RabbitMQ後不會知道消費者(C)處理成功或者失敗(甚至連有沒有消費者來處理這條消息都不知道)。
但實際的應用場景中,咱們極可能須要一些同步處理,須要同步等待服務端將個人消息處理完成後再進行下一步處理。這至關於RPC(Remote Procedure Call,遠程過程調用)。
在RabbitMQ中也支持RPC。


RabbitMQ實現RPC的機制是:
客戶端發送請求(消息)時,在消息的屬性(MessageProperties,在AMQP協議中定義了14中properties,這些屬性會隨着消息一塊兒發送)中設置兩個值 replyTo (一個Queue名稱,用於告訴服務器處理完成後將通知個人消息發送到這個Queue中) 和correlationId (這次請求的標識號,服務器處理完成後須要將此屬性返還,客戶端將根據這個id瞭解哪條請求被成功執行了或執行失敗)。
服務器端收到消息並處理服務器端處理完消息後,將生成一條應答消息到replyTo指定的Queue,同時帶上correlationId屬性客戶端以前已訂閱replyTo指定的Queue,從中收到服務器的應答消息後,根據其中的correlationId屬性分析哪條請求被執行了,根據執行結果進行後續業務處理。


總結

一、主要介紹消息隊列的概念
二、消息隊列的做用和使用場景
三、rabbitmq的特色
四、rabbitmq基本概念和內部結構
五、rabbitmq經常使用四種路由機制
六、rabbitmq的RPC調用實現原理



                         更多精彩,關注我吧。





本文分享自微信公衆號 - 跟着老萬學java(douzhe_2019)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索