消息中間件(三) 之 RabbitMQ延遲隊列

延遲任務

什麼是延遲任務

需要延遲一段時間才需要處理的任務. 比如訂單關閉, 電商平臺一般會給用戶30分鐘左右交錢時間, 當超時未交錢就需要關閉訂單. 訂單的延時關閉就是一種延遲任務.

怎麼實現延遲任務

定時任務

最普遍的做法應該就是定時任務了, 比如訂單關閉例子, 我們會將訂單存儲在表中, 通過定時任務定時掃表, 比如10分鐘一次, 對掃描結果進行時間處理, 如果是超時訂單則執行關閉操作.
定時任務實現簡單, 缺點是時間延遲時間不準確, 在訂單例子中, 如果第一次掃描發現訂單爲29分鐘未支付, 那麼該訂單只能在第二次掃描時執行關閉, 此時訂單已經是39分鐘未支付了.
爲了提供時間準確性, 我們可以減少定時任務時間, 比如一分鐘一次. 時間越短準確性越高, 但是資源消耗的也越多.

RabbitMQ延遲隊列

RabbitMQ本身沒有延遲隊列的概念, 但是它在處理死信時使用了類似的功能. 當隊列中出現死信, 我們可以讓它路由到指定的隊列中, 然後再消費該隊列消息, 達到延遲功能.
那麼什麼是死信 dead-lettered message?
官網解釋在以下三種情況下message可以成爲dead-lettered message
1 The message is negatively acknowledged by a consumer using basic.reject or basic.nack with requeue parameter set to false.
2 The message expires due to per-message TTL; or
3 The message is dropped because its queue exceeded a length limit

準確譯文
1 被女神(消費者)拒絕的, 並且沒有女朋友(requeue = false)就不讓回家(重入隊列)的你
2 歲數太大(達到ttl time to live)被公司辭退的你
3 站在車門口, 怎麼也擠不上公交車(隊列已滿)的你
滿足任意一個條件的話那你就可以稱爲~死信了

擦乾眼淚我們繼續看你的歸處~
如果隊列在聲明的時候設置了dlx(dead letter exchange 就是一個Exchange), 當你滿足條件的時候, queue會自動將你路由到該隊列, 如果好巧不巧的這時候dlx還沒有聲明, 或者queue在聲明的時候沒有設置dlx, 那麼你會像屁一樣消失在這個世界, 還不能是響屁, 官網說的if it is missing then, the messages will be silently dropped.

合上下巴, 回頭想想如何自救
對於第一種情況, 只能告訴你, 認清自己, 和父母搞好關係(.)
對於第三種情況, 早起5分鐘能死麼?
重點是第二種, 超時正好對應我們的延遲功能. 時間一天天過, 雖然你面相18, 實際已經過了三次本命年. 時間面前任何人任何事都是渣渣, 你能做的就是努力提升自己, 讓你的實力 >= 年齡, 一直進步, ttl過期就是你走到更高level(英語已過CET-20)的時候.
努力要有目標, 在進入公司時就要有. 開始創建你的職業生涯~
聲明職業生涯

名詞解釋

x-message-ttl 隊列中消息存活時間, 單位ms, 超時則認爲是死信
x-dead-letter-exchange 出現死信時路由到該參數指定的Exchange(dlx)
x-dead-letter-routing-key dlx路由到其他隊列使用的routingKey

x-message-ttl屬性就是我們可以利用的延遲時間, 設置好上面三個屬性, 然後最後消費死信最終路由到的隊列, 就完成了一個延遲任務的功能.
創建e.opportunity並通過r.raise綁定q.senior.engineer
延遲隊列相關的設置好了, 還缺一個入口, 聲明e.send, 用來發送消息到q.intermediate.engineer .
在控制檯發送消息

成爲一箇中級工程師

30歲了! 恭喜你更進一步~

在這裏可以看到一些參數, 比如成爲死信的原因, 死信從哪個隊列來的等.

policy

上面的步驟基本就可以實現RabbitMQ的延遲隊列功能, 但是有個小問題, 如果我們想改變延遲時間怎麼辦? 在RabbitMQ中, 一旦聲明瞭隊列或者Exchange, 那麼設置的屬性是無法修改的, 像上面設置的ttl我們是沒有辦法在運行時修改的, 這種情況下, 我們只好重新創建一個隊列, 設置指定的ttl. 那麼有沒有可以運行時修改延遲時間的辦法呢? 有的~
RabbitMQ中運行時修改的參數叫做parameter, parameter不僅可以運行時修改, 還可以給集羣中多個節點設置統一屬性. 而policy就是某些特殊parameter, 其中就包括我們上線提到的ttl, dlx等.

設置policy很簡單

這裏的演示就有你來完成吧~ 需要注意的是運行時修改的message-ttl對於已經入隊列的消息是無效, 這個也很合理, 否則也無法計算失效時間. dead-letter-exchange運行時修改對於入隊列的消息是有效的. 猜想下這裏的邏輯, 消息入隊列, 根據隊列message-ttl設置消息ttl, 當消息超時, 根據此時隊列的dead-letter-exchange進行路由.

RocketMQ

內置18種消息延遲隊列, 看起來理念和RabbitMQ差不多, 這個後面補一篇文章學習下

redis

設置key失效時間, 失效通知. 同上

kafka

時間輪~同上

總結

學習了RabbitMQ如何實現延遲任務, 並提供了其他幾種實現(雖然作者還沒有看…). 後面繼續補充其他實現(really?)

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