定時任務沒觸發 10W定時任務,如何高效觸發超時

2021-10-16 10:04:08 字數 1587 閱讀 2391

需求背景

1.延遲訊息功能。例如:滴滴打車訂單完成後,如果使用者一直不評價,48小時後會將自動評價為5星。

2.無效連線斷開。在im系統中,客戶端會與服務端建立大量的長連線,當客戶端與服務端30s內沒有心跳的話,需要把這個連線斷開。

一、最傳統的方案

建立一張延遲訊息表,滴滴訂單完成後插入一條延遲訊息,訊息的傳送時間為當前時間+48小時,開啟乙個定時任務每小時掃瞄一次延遲訊息表,傳送已達到觸發時間的訊息,訊息消費後將訂單評價為5星。

缺點:1.輪訓效率非常低

2.每次定時任務掃表都要全量掃瞄,有重複計算的問題

3.時效性不好,如果每小時輪訓一次,最差情況,時間誤差會達到1小時

二、高效延時訊息方案

高效延時訊息,包含兩個重要的資料結構:

環形佇列,例如可以建立乙個包含3600個slot的環形佇列(本質是乙個陣列)

任務集合,環上每個slot是乙個任務集合set

實現思路:啟動乙個timer,每隔1s在上述環形佇列移動一格,有乙個current index指標來標識當前正在檢測的slot。

task主要包含的資料為:cycle-num和task-fuction

假如我們有個訊息需要延遲3611秒傳送,我們要如何儲存這個訊息?

2.計算出該task應該放在哪個slot上,slot_index=currentindex+(延遲傳送時間%slot個數),假設此時currentindex=1,slot_index=3611%3600+1=12,所以將task放入index為12的slot中

3.將task的task-fuction指向實際要執行的任務指標

如何實時觸發要執行的延遲訊息?

啟動乙個timer,每隔1s在環形佇列移動一格currentindex++,檢查當時currentindex指向的slot中的task,看下是否有task需要執行。將task的cycle_num-1,如果減一後cycle_num等於0,執行該task。如果cycle_num不等於0,則不執行任務。

該方案優點:

(1)無需再輪詢全部訂單,效率高

(2)乙個訂單,任務只執行一次

(3)時效性好,精確到秒(控制timer移動頻率可以控制精度)

三、採用堆來實現高效能定時器

1.根據task的執行時間來構建乙個小頂堆

2.根據當前時間來計算距離小頂堆的頂點task執行,還需多長時間。假設當前時間是9點,task1的延遲執行間隔為:10點-9點=1小時,建立乙個timer執行時間為1小時後。

3.timer執行時,獲取堆的頂點節點,判斷頂點task的執行時間是否跟當前時間一致,時間一致則執行任務

4.刪除task1,把task2放入堆的頂點中,重新第2步開始執行。

10w定時任務,如何高效觸發超時

很多時候,業務有定時任務或者定時超時的需求,當任務量很大時,可能需要維護大量的timer,或者進行低效的掃瞄。一般來說怎麼實現這類需求呢?方案一 只啟動乙個timer,但需要輪詢,效率較低 方案二 不需要輪詢,但每個請求包要啟動乙個timer,比較耗資源 廢話不多說,三個重要的資料結構 1 30s超...

10w定時任務,如何高效觸發超時

二 環形佇列法 廢話不多說,三個重要的資料結構 1 30s超時,就建立乙個index從0到30的環形佇列 本質是個陣列 2 環上每乙個slot是乙個set,任務集合 3 同時還有乙個map,記錄uid落在環上的哪個slot裡 同時 1 啟動乙個timer,每隔1s,在上述環形佇列中移動一格,0 1 ...

linux定時任務 at定時任務

at命令是一次性定時計畫任務,at的守護程序atd會以後臺模式執行,檢查作業佇列來執行作業。atd守護程序會檢查系統上的乙個特殊目錄來獲取at命令的提交的作業,預設情況下,atd守護程序每60秒檢查一次目錄,有作業時,會檢查作業執行時間,如果時間與當前時間匹配,則執行此作業。注意 at命令是一次性定...