RabbitMQ 入門系列:9、擴充套件內容:死信佇列:真不適合當延時佇列。

2022-08-31 18:02:43

系列目錄

RabbitMQ 入門系列:1、MQ的應用場景的選擇與RabbitMQ安裝。

RabbitMQ 入門系列:2、基礎含義:連結、通道、佇列、交換機。

RabbitMQ 入門系列:3、基礎含義:持久化、排它性、自動刪除、強制性、路由鍵。

RabbitMQ 入門系列:4、基礎編碼:官方SDK使用:連結建立、單例改造、傳送訊息、接收訊息。

RabbitMQ 入門系列:5、基礎編碼:交換機的進階介紹及編碼方式。

RabbitMQ 入門系列:6、保障訊息:不丟失:傳送方、Rabbit儲存端、接收方。

RabbitMQ 入門系列:7、保障訊息:不重複消費:產生訊息的唯一ID。

RabbitMQ 入門系列:8、擴充套件內容:接收資訊時:可否根據RoutingKey過濾監聽資訊,答案是不能。

RabbitMQ 入門系列:9、擴充套件內容:死信佇列:真不適合當延時佇列。

RabbitMQ 入門系列:10、擴充套件內容:延時佇列:延時佇列外掛及其有限的適用場景。

前言:

延遲佇列用於事件發生後間隔一段時間後需要做特定處理的場景,如:

1、電商支付系統中,使用者下單後N分鐘不支付,自動取消訂單。
2、使用者瀏覽商品長時間後還沒下單,後續推播相關產品和優惠券。
3、使用者註冊或修改生日後:生日簡訊推播等。
4、7天后的自動確認收貨等。。。
......

對於這類應用,用訊息佇列,對個別可能是合適的,但對整個系統應用而言,它是不靠譜的。

訊息佇列的核心應用,是保持記憶體的佇列,不斷的產生並不斷的消耗,最佳狀態的保持系統的穩定和流暢。

而延遲佇列的核心,是積壓訊息,大量積壓訊息,這明顯與訊息佇列的設計就不符合。

下面來看看網傳用死信佇列來實現延遲佇列的方式

1、死信佇列的概念:

1、預設佇列的訊息過期了,或是被拒約處理,系統就是直接丟棄掉的。

2、如果你不希望過期的訊息,被系統直接丟棄,還想拿來二次處理,那麼:

可以通過繫結另一個佇列,並標識為「x-dead-letter-exchange」,

那麼,原本要丟棄的訊息,就都轉發到這指定的佇列中,這個接收丟棄資訊的佇列,就叫死信佇列。

2、死信佇列的編碼:

using (var channel = Rabbit.Instance.DefaultConnection.CreateModel())
{
    //定義普通佇列來接收丟棄的資訊
    channel.QueueDeclare("dead");

    IDictionary<string, object> dic2 = new Dictionary<string, object>();
    dic2.Add("x-dead-letter-exchange", "");//使用預設交換機
    dic2.Add("x-dead-letter-routing-key", "dead");//設定轉移到的佇列
    dic2.Add("x-message-ttl", 6000);//設定過期時間
    channel.QueueDeclare("sendtodead", arguments: dic2);

    channel.BasicPublish("", "sendtodead", false, null, Encoding.UTF8.GetBytes("6秒就過期了1。"));
    channel.BasicPublish("", "sendtodead", false, null, Encoding.UTF8.GetBytes("6秒就過期了2。"));

}

 執行後,訊息從sendtoddead佇列6秒過期後,轉移到dead佇列。

3、死信佇列它的適用場景:

1、佇列有統一的過期時間,不能使用單個資訊的過期時間:

因為MQ不掃整個佇列,只掃描佇列第1個,判斷是否過期,因此要求先進佇列的必須先過期。

2、過期時間應該較短(根據可能積壓的資料考量時間,一個核心的考量資料量是:10萬條-100萬條),避免長時間積壓資料

對於長時間不消費的,不應該存入MQ,畢竟MQ的核心是記憶體佇列,而不是磁碟佇列。

4、死信佇列它為什麼不適合當延時佇列:

瞭解完死信佇列,會發現,其實在一個系統中,僅有比如N分鐘後要處理邏輯的場景,比較適合,

其它N天后要處理的,都不靠譜。

而你用了N分鐘的場景,那其它場景你用不用?

用了,不靠譜!

不用,得用其它方案,方案會不會多樣化,不方便管理?

總結:

1、如果非要用死信佇列當延時佇列,那麼要建立很多個第N分鐘過期的佇列。

2、如果非要用死信佇列當延時佇列,那麼下一篇介紹的官方的延時佇列外掛,會比死信佇列更合適。