我們一起來學RabbitMQ 三:RabbiMQ 死信佇列,延遲佇列,持久化等知識點

小魔童哪吒發表於2021-10-07

我們們今天再來進一步學習一下 RabbitMQ 的知識點,整理了如下相關知識點

  • RabbitMQ 訊息流向是如何走的
  • 交換機相關的知識點
  • 佇列相關的知識點
  • 死信佇列,延遲佇列,持久化
  • 佇列中傳輸訊息的保障機制有哪些
  • 生產者確認的問題有哪些
  • 消費者消費的模式有哪些

RabbitMQ 訊息流向是如何走的 ?

生產者傳送訊息的時候

  • 生產者連線到 RabbitMQ Broker,建立一個連線,開啟一個通道

  • 生產者宣告一個交換機,並設定相關屬性,例如交換機型別、是否持久化等

  • 生產者宣告一個佇列並設定相關屬性,例如是否排他、是否持久化、是否自動刪除等

  • 生產者通過路由鍵將交換機和佇列繫結起來

  • 生產者傳送訊息至 RabbitMQ Broker,其中包含路由鍵、交換機等資訊

  • 相應的交換機根據接收到的路由鍵查詢相匹配的佇列

  • 如果找到,則從生產者傳送過來的訊息存入相應的佇列中

  • 如果沒有找到,則根據生產者配置的屬性選擇丟棄還是回退給生產者

  • 關閉訊號

  • 關閉連線

消費者接收訊息的過程

  • 消費者連線到 RabbitMQ Broker,建立一個連線,開啟一個通道

  • 消費者向 RabbitMQ Broker請求消費相應佇列中的訊息,可能會設定相應的回撥函式,以及做一些準備工作

  • 等待RabbitMQ Broker回應並投遞相應佇列中的訊息,消費者接收訊息

  • 消費者確認接收到的訊息

  • RabbitMQ 從佇列中刪除相應已經被確認的訊息

  • 關閉通道

  • 關閉連線

常用的交換機都有哪些?

不同交換機有不同交換機的特性

  • fanout

適合釋出訂閱式,廣播的方式來傳遞訊息

  • direct

適合路由到指定佇列的傳輸訊息

  • topic

與上述交換機類似,只是多了萬用字元

  • headers

會匹配訊息的 headers,易用性較差

fanout exchange 可以做成備份的交換機,因為 fanout 的訊息是廣播的方式

若A生產者A訊息傳送到A交換機,路由到A佇列,若A訊息填寫的路由 key 與 A佇列的繫結 key 不對齊,則會被重新傳送到 另外一個備份 fanout 交換機上

  • 如果設定的備份交換機不存在,訊息會丟失
  • 如果設定的備份交換機沒有繫結任何佇列,訊息會丟失
  • 如果設定的備份交換機沒有任何匹配的佇列,訊息會丟失

佇列相關知識點有哪些?

設定 訊息的TTL

  • 通過佇列屬性x-message-ttl(單位毫秒)設定,佇列中所有訊息都有相同的過期時間
  • 對訊息本身進行單獨設定,每條訊息的TTL可以不同

若兩種方式一起使用,則訊息的TTL以兩者之間較小的那個數值為準

訊息在佇列中的生存時間一旦超過設定的TTL值時,就會變成死信,消費者將無法再收到該訊息

另外對於TTL 的 2 種情況:

  • 如果不設定 TTL ,則表示此訊息不會過期
  • 如果將 TTL 設定為 0,則表示除非此時可以直接將訊息投遞到消費者,否則該訊息會被立即丟棄

設定佇列的 TTL

通過佇列屬性x-expires可以控制佇列被自動刪除前處於未使用狀態的時間,未使用狀態的時間 有如下含義:

  • 佇列上沒有任何的消費者
  • 佇列也沒有被重新宣告

死信佇列是什麼

當訊息在一個佇列中變成死信之後,它能重新被髮送到另一個交換機中,這個交換機就是 死信交換機,繫結死信交換機 的佇列就稱之為死信佇列

訊息變成死信有這幾種情況:

  • 訊息被拒絕了
  • 訊息過期了
  • 佇列達到了最大的長度

這個 死信交換機,也是一個正常的交換機

可以被任何一個佇列指定,被指定成死信交換機的時候,會設定 x-dead-letter-exchange屬性,並且會設定對應的路由鍵 x-dead-letter-routing-key

死信佇列的應用場景有哪些

  • 處理異常情況

訊息不能夠被消費者正確消費而被置入死信佇列中的情況,後續分析程式可以通過消費這個死信佇列中的內容來分析當時所遇到的異常情況,進而可以改善和優化系統

  • 搭配 TTL 模擬延遲佇列

延遲佇列是什麼?

訊息傳送到佇列之後,並不期望消費者能馬上消費,也是延遲一段時間之後,才拿到該訊息進行消費。

延遲佇列我們是使用 死信佇列 和 TTL 來模擬 延遲佇列

延遲佇列使用的場景舉個例子:

  • 下單了一個外賣,需要在15分鐘以內完成支付,若未按時完成,則屬於異常處理,需要延遲佇列來處理這些訊息

本例子中,使用者下單,將訊息丟入佇列中,TTL 為15分鐘,若15還未完成支付,則訊息會被丟入對應的 死信佇列中進行處理

優先順序佇列是什麼?

指的是 具有高優先順序的佇列具有最高的優先權,優先順序高的訊息具備優先被消費的特權

可以通過 設定 x-max-priority 來設定 優先順序佇列

當然,如果在消費者的消費速度遠大於生產者的速度,且 Broker 沒有訊息堆積的情況下,對傳送的訊息設定優先順序沒有什麼實際意義,因為生產者生產的訊息,都能很快的被消費者立刻消滅掉

持久化都有哪些?

為了提高 RabbitMQ 的可靠性,RabbitMQ 做了持久化,持久化有這三部分

  • 交換機的持久化

RabbitMQ服務重啟,若交換機不設定持久化,交換機的後設資料會丟失,訊息不會丟失,不過訊息再也不能傳送到這個交換機中了

  • 佇列的持久化

RabbitMQ服務重啟,若佇列不設定持久化,後設資料會丟失,資料也會丟失

  • 訊息的持久化

設定所有的訊息持久化,可靠性會大大提高,可是對於效能上是一個巨大的影響,這是一個可靠性和吞吐量之間做一個權衡

佇列中傳輸訊息有哪些保障的機制?

訊息的傳輸保障,對於一般的訊息中介軟體來說,會考慮這三個層級

  • 最多一次

訊息可能會丟失,但不會重複

其中最多一次投遞實現需要考慮以下幾個方面的內容:

  1. 訊息生產者需要開啟事務機制 或者 確認機制,以確保訊息可以可靠地傳輸到 RabbitMQ 中

  2. 訊息生產者需要配合使用備份交換機來確保訊息能夠從交換機路由到佇列中,進而能夠儲存下來而不會被丟棄

  3. 訊息和佇列都需要進行持久化處理,以確保 RabbitMQ 伺服器在遇到異常情況時不會造成訊息丟失

  4. 消費者在消費訊息的同時需要將autoAck設定為 false,然後通過手動確認的方式去確認已經正確消費的訊息,以避免在消費端引起不必要的訊息丟失

  • 最少一次

訊息可能會重複,但不會丟失

生產者隨意傳送,消費者隨意消費

  • 恰好一次

每條訊息一定只會被傳輸一次

RabbitMQ 這邊 支援最多一次和至少一次

恰好一次是 RabbitMQ 無法保障的,會有這樣幾個原因

  1. 消費者在消費完一條訊息之後向 RabbitMQ 傳送確認命令

    此時由於異常原因(網路,或當機)造成RabbitMQ並沒有收到這個確認命令,RabbitMQ不會將此條訊息標記刪除。

    在重新連線之後,消費者還是會消費到這一條訊息,這就造成了重複消費

  2. 生產者在使用 確認機制 的時候,傳送完一條訊息等待 RabbitMQ 返回確認通知

    此時正好網路斷開,生產者捕獲到異常情況

    為了確保訊息可靠性選擇重新傳送,這樣 RabbitMQ 中就有兩條同樣的訊息,在消費的時候,消費者就會重複消費

那麼生產者確認問題呢?

RabbitMQ 中的生產者確認機制有 兩種模式

  • 事務模式

事務模式效能非常低,不建議使用。

事務機制在一條訊息傳送之後會使傳送端阻塞,以等待RabbitMQ的回應,之後才能繼續放下一條訊息,這種方式會影響效能,所以不建議使用

  • 傳送方確認模式 confirm 模式

傳送方確認機制最大的好處在於它是非同步的,一旦釋出一條訊息,生產者就可以在等通道返回確認的同時繼續傳送下一條訊息

當訊息最終得到確認之後,生產者便可以通過回撥方式來處理該確認訊息,哪怕是 RabbitMQ 自己內部出現了錯誤,也會回覆響應的應答給到生產者 例如Nack

消費者處理訊息的模式有哪些?

  • 推模式

消費者正常啟動程式之後,會是推模式

  • 拉模式

在消費者程式第一次起來的時候,是拉模式

參考資料:

RabbitMQ Tutorials

歡迎點贊,關注,收藏

朋友們,你的支援和鼓勵,是我堅持分享,提高質量的動力

好了,本次就到這裡

技術是開放的,我們的心態,更應是開放的。擁抱變化,向陽而生,努力向前行。

我是小魔童哪吒,歡迎點贊關注收藏,下次見~

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章