RabbitMq基礎教程之基本概念

weixin_34148456發表於2018-05-28

RabbitMQ是一個訊息佇列,和Kafka以及阿里的ActiveMQ從屬性來講,乾的都是一回事。訊息佇列的主要目的實現訊息的生產者和消費者之間的解耦,支援多應用之間的非同步協調工作

由於工作原因,接觸和使用rabbitmq作為生產環境下的訊息佇列,因此準備寫一些博文,記錄下這個過程中的收貨;而開篇除了環境搭建之外,就是對於其內部的基本概念進行熟悉和了解了。

基礎環境搭建可以參考: 《RabbitMq基礎教程之安裝與測試》

本文則主要集中在以下幾點:

  • 幾個基本概念(Message, Publisher, Exchange, Binding, Queue, Channel, Consuer, Virtual host)
  • 訊息分發的幾種策略
  • ACK是什麼鬼

I. 基本概念

1. 訊息佇列

首先來一張訊息佇列的經典圖,可以劃分為三個角色: Producer, Queue, Consumer

1405936-e1d4a962e90b21bd.jpg
IMAGE
  • Queue:為承載訊息的容器,為什麼是佇列而不是棧呢?主要是因為絕大部分的場景,我們都是希望訊息是先進先出,有順序的
  • Producer:生產者,就是產生訊息,並不斷往佇列塞的角色
  • Consumer:消費者,也就是不斷從佇列中獲取訊息的角色

看到這個模型,如果對JDK的容器有一定的瞭解,很容易可以想到藉助 ArrayBlockingQueue 或者 ListBlockingQueue 就可以實現簡易的訊息佇列(也就是我們常說的生產者-消費者模型)

2. 例項理解訊息佇列

其實在生活中,這種模型用得非常多,就比如我們都會接觸的網購快遞,可以說是一個典型的訊息佇列的case了:

商家不斷的把商品扔給快遞公司(注意不是直接將商品給買家),而快遞公司則將商品根據地質分發對應的買家

對上面這個過程進行拆解,可以對映扮演的角色

  • 商品:Message,傳遞的訊息,由商家投遞給快遞公司時,需要進行打包(一般Producer生產訊息也會將實體資料進行封裝)
  • 商家:Produer 生產者
  • 快遞公司: Queue,訊息的載體
  • 買家:Consumer 消費者

那麼快遞公司時怎麼知道要把商品給對應的買家呢?根據包裹上的地址+電話

  • 同樣訊息佇列也需要一個對映規則,實現Message和Consumer之間的路由

3. RabbitMQ基本概念

通過上面的例項對比,發現基本的訊息佇列定義的元素太少,這裡則正好可以看一下RabbitMQ是怎麼具體來實現訊息佇列的

1405936-3601211b451f4824.jpg
內部結構圖
  • Message:訊息,包含訊息頭(即附屬的配置資訊)和訊息體(即訊息的實體內容)
  • Publisher:生產者,向交換機發布訊息的主體
  • Exchange:交換機,用來接收生產者傳送的訊息並將這些訊息路由給伺服器中的佇列
  • Binding:繫結,用於給Exchange和Queue建立關係,就是我們熟知的配對的紅娘
  • Queue:訊息佇列,用來儲存訊息直到傳送給消費者。它是訊息的容器,也是訊息的終點。一個訊息可投入一個或多個佇列。訊息一直在佇列裡面,等待消費者連線到這個佇列將其取走。
  • Connection:連線
  • Channel:通道,MQ與外部打交道都是通過Channel來的,釋出訊息、訂閱佇列還是接收訊息,這些動作都是通過Channel完成;簡單來說就是訊息通過Channel塞進佇列或者流出佇列
  • Consumer:消費者,從訊息佇列中獲取訊息的主體
  • Virtual Host: 虛擬主機,表示一批交換器、訊息佇列和相關物件。虛擬主機是共享相同的身份認證和加密環境的獨立伺服器域。每個 vhost 本質上就是一個 mini 版的 RabbitMQ 伺服器,擁有自己的佇列、交換器、繫結和許可權機制。vhost 是 AMQP 概念的基礎,必須在連線時指定,RabbitMQ 預設的 vhost 是 /
  • Broker:訊息佇列伺服器實體

上面是一些專業的概念,那麼可以怎麼對映到前面的快遞上呢?

II. Exchange型別

生產者,將訊息投遞給Exchange,然後由Exchange將訊息路由到對應的Queue上,供消費者消費,那麼這個路由有哪些方式呢?

1. Direct策略

1405936-24ef7841780968ea.jpg
IMAGE

訊息中的路由鍵(routing key)如果和 Binding 中的 binding key 一致, 交換器就將訊息發到對應的佇列中

簡單來講,就是路由鍵與佇列名完全匹配

  • 如果一個佇列繫結到交換機要求路由鍵為“dog”
  • 只轉發 routing key 標記為“dog”的訊息,
  • 不會轉發“dog.puppy”,也不會轉發“dog.guard”等等
  • 它是完全匹配、單播的模式

舉例說明

1405936-6670672261849a70.jpg
IMAGE

Exchange和兩個佇列繫結在一起:

  • Q1的bindingkey是orange
  • Q2的binding key是black和green.
  • 當Producer publish key是orange時, exchange會把它放到Q1上, 如果是black或green就會到Q2上, 其餘的Message被丟棄

2. Fanout策略

1405936-9bbec1f61056ceed.jpg
IMAGE

從上圖也可以看出,這種策略,將忽略所謂的routing key,將訊息分發到所有繫結的Queue上,更加類似我們理解的廣播模式

3. Topic策略

1405936-092f1e533d018f83.jpg
IMAGE

topic 交換器通過模式匹配分配訊息的路由鍵屬性,將路由鍵和某個模式進行匹配,此時佇列需要繫結到一個模式上

可以理解為直接策略的進階版,直接策略是完全精確匹配,而topic則支援正則匹配,滿足某類指定規則的(如以xxx開頭的路由鍵),可以鍵訊息分發過去

  • # 匹配0個或多個單詞
  • * 匹配不多不少一個單詞

一個更直觀的例項如下

1405936-41ada22745c87ac6.jpg
IMAGE

Producer傳送訊息時需要設定routing_key,

  • Q1 的binding key 是”.orange.“
  • Q2 是 “..rabbit” 和 “lazy.#”:
  • 產生一個 test.orange.mm 訊息,則會路由到Q1;而如果是 test.orange則無法路由到Q1,因為Q1的規則是三個單詞,中間一個為orange,不滿足這個規則的都無效
  • 產生一個 test.qq.rabbit 或者 lazy.qq 都可以分發到Q2;即路由key為三個單詞,最後一個為rabbit或者不限制單詞個數,主要第一個是lazy的訊息,都可以分發過來
  • 如果產生的是一個 test.orange.rabbit訊息,則Q1和Q2都可以滿足

4. Headers策略

這個實際上用得不多,它是根據Message的一些頭部資訊來分發過濾Message,忽略routing key的屬性,如果Header資訊和message訊息的頭資訊相匹配

5. 小結

主要使用的訊息分發策略有三個,直接,路由和扇形,簡單的小結下應用場景和區別

a. Direct Exchange

直接完全匹配模式,適用於精準的訊息分發

b. Topic Exchange

Routing Key的匹配模式,支援Routing Key的模糊匹配方式,更適用於多類訊息的聚合

c. Fanout Exchange

忽略Routing Key, 將訊息分配給所有的Queue,廣播模式,適用於訊息的複用場景

III. ACK

訊息佇列的一個重要指標,當有消費者獲取了訊息之後,對這個訊息我應該怎麼辦?是直接刪除還是等某個合適的機會再刪除?又或者是乾脆不刪除,就留著了?

在實際的應用場景中,訊息正常消費之後,我們希望的是這個訊息就不要了,但是消費的過程中如果出現了bug,則希望不要刪除訊息,等我修復這個bug後,可以把這個訊息重新的投遞給我

1. ack機制

Consumer接收到了訊息之後,必須返回一個ack的標誌,表示訊息是否成功消費,如果返回true,則表示消費成功了,然後這個訊息就會從RabbitMQ的佇列中刪掉;如果返回false,且設定為重新入隊,則這個訊息可以被重新投遞進來

通常實際編碼中,預設是自動ACK的,如果訊息的重要性程度較高,我們應該設定為主動ACK,在接收到訊息之後,自主的返回對應的ACK資訊

這一塊更多地內容可以檢視實際使用篇

IV. 其他

1. 參考

2. 一灰灰Bloghttps://liuyueyi.github.io/hexblog

一灰灰的個人部落格,記錄所有學習和工作中的博文,歡迎大家前去逛逛

3. 宣告

盡信書則不如,已上內容,純屬一家之言,因個人能力有限,難免有疏漏和錯誤之處,如發現bug或者有更好的建議,歡迎批評指正,不吝感激

4. 掃描關注

1405936-a7f81b50c6f3176f.png
QrCode

相關文章