需求背景
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命令是一次性定...