延時訊息大致設計

2022-09-21 14:57:13 字數 1125 閱讀 9236

延時訊息,顧名思義就是傳送訊息後延遲多少時間接收。

使用場景舉例,例如使用者買票後,出票後要給使用者發乙個反現金紅包,但是出票一般是非同步出票,所以我們可以設定乙個最大時間,例如30分鐘。在買票30分鐘後,根據出票結果決定是否發反現金紅包。此時就可以使用延時佇列,在使用者購票的時候傳送乙個30分鐘的延時訊息,在接收到延時訊息後查出票結果決定是否發紅包。

實現方式可如下幾種

在傳送延時訊息時,可以根據當前時間算出任務要執行的時間,然後將資料存入儲存系統中,定時器每間隔時間去掃瞄,如果掃瞄到執行時間在當前時間之前且還未執行的,則將任務取出來執行,並標記為已執行

這個方法延時精確度依賴於掃瞄頻率,資料量變大後掃瞄效率將變低o(n) 複雜度

可以利用小頂堆的特性,將延時任務構建成乙個堆,這樣只需每次檢視堆頂的時間點任務是否在當時時間之後,如果是的話就取堆頂的任務執行。j**a中的延時佇列delayqueue就是這個設計

該方法精準度較高,但取任務以及加任務的時候由於要重新維持堆,所以仍要logn的複雜度,在資料量較大的情況效率仍會變低

該方法可以理解為定時器的優化版,主要優化了定時器的儲存和掃瞄問題

例如以乙個小時的時間輪為例,使用者投遞的延時訊息,我們根據投遞時間加延時時間算出最終需要的投遞時間,然後將這些訊息按小時維度儲存到檔案中,例如2022021611,2022021612,2022021612...,並對這些檔案建立索引,檔案裡面要儲存的資訊大概如下

然後在記憶體裡面用乙個執行緒維護乙個60分鐘時間輪,以秒為單位可以分為3600個時間槽,系統每過一秒就將當前時間槽裡面的任務取出來投遞,然後可以固定在時間跑到最後乙個槽的時候載入下乙個小時的檔案。將檔案後的資訊解析根據執行的time時間戳(一般用秒),放入其對應的時間槽,例如有個訊息是下乙個小時的第10分鐘解析也就是會放入到第600個槽裡面,這樣當前的時間輪跑到3600之後又會重新從0開始,然後跑到600的時候將第600個槽裡面剛放入的訊息取出來投遞。

這個方法的好處是系統記憶體裡面只會載入當前時間輪的訊息,剩下的全部存在磁碟上,解決了海量訊息投遞的問題。時間精準度也很高 (公司目前用的該種實現方式)

時間輪的設計不止可以用到延時佇列,還有心跳檢測,超時檢測等都是可以的。

實現延時訊息

基於外部儲存的方案本質上都是乙個套路,將 mq 和 延時模組 區分開來,延時訊息模組是乙個獨立的服務 程序。延時訊息先保留到其他儲存介質中,然後在訊息到期時再投遞到 mq。1.1 基於 資料庫 如mysql 基於關係型資料庫 如mysql 延時訊息表的方式來實現。create table delay...

MQ如何實現訊息延時

很多時候,業務有 在一段時間之後,完成乙個工作任務 的需求。例如 滴滴打車訂單完成後,如果使用者一直不評價,48小時後會將自動評價為5星。一般來說怎麼實現這類 48小時後自動評價為5星 需求呢?常見方案 啟動乙個cron定時任務,每小時跑一次,將完成時間超過48小時的訂單取出,置為5星,並把評價狀態...

延時job設計

目前系統系統job任務是每10分鐘重試一次,總共重試7次。所有需要重試的請求都在10分鐘之內堆積,如果請求量過大,這個時間點壓力都有可能落到資料庫上面,從而造成資料庫崩潰。此外時間配置不夠智慧型化。如果兩小時之後所依賴的第三方系統穩定,而目前的重發機制相當於失效了。基於上面兩個原因,提出了改進方案,...