1. 程式人生 > >延時任務排程系統——技術選型

延時任務排程系統——技術選型

      經常會有這樣的需求,包含大量的延時執行任務

1,如一個代辦事項app,代辦實現可以設定觸發時間,像鬧鐘一樣。

2,如美團的訂單,下單後10分鐘不支付,會自動取消。

3,淘寶使用者7天不確認收貨,自動確認收貨。

諸如以上需求,需要的就是一個延時任務執行系統。實現的方案有很多,各有優劣:

一,為每個任務建立一個倒計時執行緒

優點:實現簡單,及時性高

缺點:嚴重浪費伺服器CPU資源,如果資料量巨大,要建立多少執行緒啊;

           執行緒和資料存在於記憶體中,宕機或redeploy後無法恢復;

二,定時任務掃描

    利用定時任務輪詢資料庫,掃描出來到時間的資料。

優點:實現簡單

缺點:掃描頻率高的話,會浪費大量的伺服器資源;

           掃描頻率低的話,及時性無法保證;

           掃描頻率中等的話,既浪費伺服器資源,又無法保證及時性。

三,改良的定時任務掃描

    將過期時間分為多個階段,如下:

1)大於1天               1天掃描一次

2)小於1天,大於1小時      1小時掃描一次

3)小於1小時,大於1分鐘    1分鐘掃描一次

4)小於1分鐘              1秒鐘掃描一次

     如上,分為4個階段(可根據具體情況再次細分),開啟4個定時任務分別進行掃描,掃描頻率由低到高,將記錄id儲存到4個redis的list中。掃描時,1)中符合條件的要被move到2)的list中,2)中符合條件的要被move到3)的list中,以此類推,4)中掃描到後立即開啟Timer或Schedule進行倒計時執行。

優點:可大大降低每次掃描所需處理的資料;

缺點:依然是定時輪詢,效率不高,伺服器資源也有浪費;

           實現也複雜;

四,Rabbitmq

    向rabbitmq釋出訊息時可以指定其ttl(time-to-live),訊息過期時會進入dead-letter-exchange

優點:高效,可以利用rabbitMq的分散式特性進行叢集擴充套件,且支援持久化

缺點:已釋出的訊息無法撤銷或修改;

           一個訊息比同一佇列的其它訊息提前過期,也無法優先進入死信佇列;

五,Redis的SortedSet

    Redis的sortedSet是個有序佇列,將過期時間作為其score,放入sortedSet中時,redis會自動按score排序。開啟一個定時任務,不斷判斷第一個元素是否到期,如果是,則從佇列中移除,並執行相關業務處理。

優點:實現簡單;

          任務可撤銷,可修改;

          redis可叢集;

缺點:需要有定時任務高頻率的訪問redis,判斷是否過期,造成CPU空耗;

六,Redis的expired_time

    向redis中新增資料時指定其過期時間,並監聽其過期事件

jedis.psubscribe(new JedisPubSub(), "__key*@0__:expired");

其中0是redis的DB_INDEX

優點:高效;

          實現簡單;

缺點:暫無發現

七,DelayQueue

    jdk中的DelayQueue就是為了這種場景而設計的,完美契合需求,將資料放入佇列時需要給出其過期時間,DelayQueue會自動將其排序,呼叫take方法,如果沒有到期的資料,執行緒會阻塞住,直到有資料到期。

    但這種方式也有缺點

1)資料存在記憶體中,需要持久化(可以自己實現),否則宕機或redeploy會丟失資料;

2)不具備分散式能力,無法叢集;

八,時間輪

    

1)時間輪是一種環裝的資料結構,分成多個格子;

2)每個格子代表一段時間,時間越短,精度越高;

3)每個格子裡都有一個任務list;

4)指標隨著時間一格一格的轉動,並執行相應格子中的任務;

    以上圖為例,假設一個格子是1秒,則整個時間輪能表示的時間段為8s, 如果當前指標指向2,此時需要排程一個3s後執行的任務,需要放到第5個格子(2+3)中,指標再轉3次就可以執行了。

缺點:1)格子數量有限,所能代表的時間有限,太多不好維護。

         2)如果時間跨度大,每次檢查的量很大,會做很多無效的檢查

         3)實現複雜,尤其是下面的分層時間輪。

    為解決問題1,可將任務的輪次放入到格子中,如一個任務是10s後執行,就是第二個輪次的第2s執行,放入當前指標的後面第2個格子,且標記其輪次為2,指標也要校驗輪次。

    為解決問題2,可以做分層時間輪,如圖:

    分層時間輪中的每個輪都有自己的格子數和時間間隔,當最底層的時間輪轉一圈時,高一層的時間輪就轉一個格子。高層的格子中的任務進入尾聲時,需要降級到底層時間輪。和方案三類似。

九,三方中介軟體

    這種型別的中介軟體很少,有如下:

以上9種方案,五六七實現簡單(其中7可自己實現下持久化),推薦

說明:

1,本文只提供大致思路,不提供具體實現

2,本文部分思路來源於網路,侵刪