RabbitMQ:從入門到搞定面試官

安裝

使用docker安裝,注意要安裝tag後綴爲management的鏡像(包含web管理插件),我這裏使用的是rabbitmq:3.8-management

1、 拉取鏡像

docker pull rabbitmq:3.8-management

2、 啓動容器

docker run --name rabbitmq --hostname rabbitmq -d -p 15672:15672 -p 5672:5672 rabbitmq:3.8-management

3、 訪問web管理頁面

http://127.0.0.1:15672/

概念介紹

組件概念

  • Broker:簡單來說就是消息隊列服務器實體。
  • Exchange:消息交換機,它指定消息按什麼規則,路由到哪個隊列。
  • Queue:消息隊列載體,每個消息都會被投入到一個或多個隊列。
  • Binding:綁定,它的作用就是把exchange和queue按照路由規則綁定起來。
  • Routing Key:路由關鍵字,exchange根據這個關鍵字進行消息投遞。
  • vhost:虛擬主機,一個broker裏可以開設多個vhost,用作不同用戶的權限分離。
  • producer:消息生產者,就是投遞消息的程序。
  • consumer:消息消費者,就是接受消息的程序。
  • channel:消息通道,在客戶端的每個連接裏,可建立多個channel,每個channel代表一個會話任務。

6種消息模式和4種交換機

消息模式:

  • Simple Work Queue (簡單工作隊列):也就是常說的點對點模式,一條消息由一個消費者進行消費。(當有多個消費者時,默認使用輪訓機制把消息分配給消費者)。
  • Work Queues (工作隊列):也叫公平隊列,能者多勞的消息隊列模型。隊列必須接收到來自消費者的手動ack纔可以繼續往消費者發送消息。
  • Publish/Subscribe (發佈訂閱模式):一條消息被多個消費者消費。
  • Routing(路由模式):有選擇的接收消息。
  • Topics (主題模式):通過一定的規則來選擇性的接收消息
  • RPC 模式:發佈者發佈消息,並且通過 RPC 方式等待結果。目前這個應該場景少,而且代碼也較爲複雜,本章不做細講。

交換機類型:

  • direct(直連交換機):將隊列綁定到交換機,消息的 routeKey 需要與隊列綁定的 routeKey 相同。
  • fanout (扇形交換機):不處理 routeKey ,直接把消息轉發到與其綁定的所有隊列中。
  • topic(主題交換機):根據一定的規則,根據 routeKey 把消息轉發到符合規則的隊列中,其中#用於匹配符合一個或者多個詞(範圍更廣), * 用於匹配一個詞。
  • headers (頭部交換機):根據消息的 headers 轉發消息而不是根據 routeKey 來轉發消息, 其中 header 是一個 Map,也就意味着不僅可以匹配字符串類型,也可以匹配其他類型數據。規則可以分爲所有鍵值對匹配或者單一鍵值對匹配。

消息模式和交換機的對應關係如下:

2021-10-20-11-17-31
2021-10-20-11-17-31

消費模式

消費模式分爲推模式(Basic Consume)和拉模式(channel basicGet)

代碼demo

瞭解完上述概念後,還是要用代碼實踐一下,以加深自己的理解。幸運的是rabbitmq官方提供了完整的代碼demo,並且包含多種語言版本。
所以可以直接下載官方示例學習:

https://github.com/rabbitmq/rabbitmq-tutorials

比如下面是python代碼中的hello world例子

20211025142123
20211025142123

進階

備份交換器

生產者在發送消息的時候如果不設置 mandatory 參數 那麼消息在未被路由的情況下將會丟失,如果設置了 mandatory 參數,那麼需要添加 ReturnListener 的編程邏輯,生產者的代碼將變得複雜。如果既不想複雜化生產者的編程邏輯,又不想消息丟失,那麼可以使用備份交換器,這樣可以將未被路由的消息存儲在 RabbitMQ 中,再在需要的時候去處理這些消息。

消息過期時間

目前有兩種方式設置消息的過期時間,一是通過隊列屬性設置,二是通過消息單獨設置。如果兩種方式同時使用,以最小值爲準。

隊列過期時間

通過 channel queueDeclare 方法中的 expires 參數可以控制隊列被自動刪除前處於未使用狀態的時間。未使用的意思是隊列上沒有任何的消費者,隊列也沒有被重新聲明,並
且在過期時間段內也未調用過Basic Get命令。

死信隊列(DLX)

DLX ,全稱爲 Dead-Letter-Exchange ,可以稱之爲死信交換器。當消息在一個隊列中變成死信 (dead message) 之後,它能被重新被髮送到另一個交換器中,這個交換器就是 DLX ,綁定 DLX 的隊列就稱之爲死信隊列。

消息變成死信一般由於以下幾種情況:

  • 消息被拒絕
  • 消息過期
  • 隊列達到最大長度

DLX 是一個正常的交換器,和一般的交換器沒有區別,它能在任何的隊列上被指定際上就是設置某個隊列的屬性。當這個隊列中存在死信時 RabbitMQ 就會自動地將這個消息新發布到設置的 DLX ,進而被路由到另一個隊列,即死信隊列。可以監聽這個隊列中的消息、以進行相應的處理。

延時隊列

在rabbitmq中可通過過期時間(TTL)和死信隊列(DLX)實現延時隊列

優先級隊列

可設置隊列支持的最大優先級,然後發送消息時設置消息的優先級。但是要注意這種情況只在消費者能力小於生產者,有消息堆積時有效。

持久化

RabbitMQ的持久化分爲3個部分:交換器的持久化、隊列的持久化和消息的持久化。但是如果將所有消息持久化,將會嚴重影響rabbitmq的性能。

即使將交換器、隊列和消息都設置了持久化,也不能保證消息100%不丟失。

  1. 從消費者端,防止消費者收到消息還沒來得及處理就宕機的情況,需要將autoAck設置爲false
  2. 從生產者斷,防止發送到rabbitmq後還沒來的及落盤rabbitmq就宕機的情況,可以在生產者端引入事務機制或者發送方確認機制來保證消息己經正確地發送並存儲RabbitMQ 中(前提還要保證在調用 channel.basicPublish 方法的時候交換器能夠將消息正確路由到相應的隊列之中)或者引入鏡像隊列來保證高可用

消息的有序性

很多資料上說rabbitmq可以保證消息的有序,其實是不嚴謹的。在不使用任何 RabbitM 高級特性 ,也沒有消息丟失、網絡故障之類異常的情況發生,並且只有一個消費者的情況下,最好也只有一個生產者的情況下可以保證消息的順序性。如果有多個生產者同時發送消息,無法確定消息到達 Broker 的前後順序,也就無法驗證消息的順序性。

如果要保證消息的順序性,需要業務方使用 RabbitMQ 之後做進一步的處理,比如在消息體內添加全局有序標識(類似SequenceID) 來實現。

惰性隊列

RabbitMQ 3.6.0 版本開始引入了惰性隊列 lazy Queue 的概念。惰性隊列會盡可能地將消息存入磁盤中,而在消費者消費到相應的消息時纔會被加載到內存中,它的一個重要的設計目標是能夠支持更長的隊列即支持更多的消息存儲。當消費者由於各種各樣的原因(比如消費者下線、宕機或者由於維護而關閉等〉致使長時間內不能消費消息而造成堆積時惰性隊列就很有必要了。

面試資料和電子書

上面進階的內容可能只是零散的知識點,如果想比較成體系的深入瞭解的話,還是建議讀本關於rabbitmq的書,個人比較推薦《RabbitMQ實戰指南。
看完後如果還想查漏補缺,或者應對面試,可以看一下網上的知識點總結或者最新的面試題彙總。


學習的最好方法就是實踐,建議大家像上面寫的那樣在自己機器上安裝學習一下,不要只停留在紙面上。

最後因爲電子書和麪試題都是PDF,所以我都上傳到了網盤,如果大家需要,可以回覆:rabbitmq,獲取一些資料。

20211025154244
20211025154244
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章