分佈式定時任務框架選型,寫得太好了!
爲什麼我們需要定時任務
我們先思考下面幾個業務場景的解決方案:
-
支付系統每天凌晨 1 點跑批,進行一天清算,每月 1 號進行上個月清算
-
電商整點搶購,商品價格 8 點整開始優惠
-
12306 購票系統,超過 30 分鐘沒有成功支付訂單的,進行回收處理
-
商品成功發貨後,需要向客戶發送短信提醒
類似的業務場景非常多,我們怎麼解決?
很多業務場景需要我們某一特定的時刻去做某件任務,定時任務解決的就是這種業務場景。一般來說,系統可以使用消息傳遞代替部分定時任務,兩者有很多相似之處,可以相互替換場景。
如,上面發貨成功發短信通知客戶的業務場景,我們可以在發貨成功後發送 MQ 消息到隊列,然後去消費 mq 消息,發送短信。
但在某些場景下不能互換:
-
時間驅動 / 事件驅動:內部系統一般可以通過時間來驅動,但涉及到外部系統,則只能使用時間驅動。如怕取外部網站價格,每小時爬一次
-
批量處理 / 逐條處理:批量處理堆積的數據更加高效,在不需要實時性的情況下比消息中間件更有優勢。而且有的業務邏輯只能批量處理。如移動每個月結算我們的話費
-
實時性 / 非實時性:消息中間件能夠做到實時處理數據,但是有些情況下並不需要實時,比如:vip 升級
-
系統內部 / 系統解耦:定時任務調度一般是在系統內部,而消息中間件可用於兩個系統間
有哪些定時任務的框架
單機
-
timer:是一個定時器類,通過該類可以爲指定的定時任務進行配置。TimerTask 類是一個定時任務類,該類實現了 Runnable 接口,缺點異常未檢查會中止線程
-
ScheduledExecutorService:相對延遲或者週期作爲定時任務調度,缺點沒有絕對的日期或者時間
-
spring 定時框架:配置簡單功能較多,如果系統使用單機的話可以優先考慮 spring 定時器
分佈式
-
Quartz:Java 事實上的定時任務標準。但 Quartz 關注點在於定時任務而非數據,並無一套根據數據處理而定製化的流程。雖然 Quartz 可以基於數據庫實現作業的高可用,但缺少分佈式並行調度的功能
-
TBSchedule:阿里早期開源的分佈式任務調度系統。代碼略陳舊,使用 timer 而非線程池執行任務調度。衆所周知,timer 在處理異常狀況時是有缺陷的。而且 TBSchedule 作業類型較爲單一,只能是獲取 / 處理數據一種模式。還有就是文檔缺失比較嚴重
-
elastic-job:噹噹開發的彈性分佈式任務調度系統,功能豐富強大,採用 zookeeper 實現分佈式協調,實現任務高可用以及分片,目前是版本 2.15,並且可以支持雲開發,這個我寫了系列教程了,在 Java 技術棧公從號可以搜索閱讀。
-
Saturn:是唯品會自主研發的分佈式的定時任務的調度平臺,基於噹噹的 elastic-job 版本 1 開發,並且可以很好的部署到 docker 容器上。
-
xxl-job: 是大衆點評員工徐雪裏於 2015 年發佈的分佈式任務調度平臺,是一個輕量級分佈式任務調度框架,其核心設計目標是開發迅速、學習簡單、輕量級、易擴展。
分佈式任務調度系統對比
參與對比的可選系統方案:elastic——job (以下簡稱 E-Job)與 xxx-job(以下簡稱 X-Job)
項目背景及社區力量
X-Job:大衆點評公司下員工許雪裏、貢獻者 3 人; github 有 2470star、1015fork | QQ 討論羣 6 個 | 有登記在使用的超過 40 家公司 | 文檔齊全
E-Job:噹噹網開源,貢獻者 17 人; github 有 2524star、1015fork | QQ 討論羣1個、源碼討論羣1個 | 有登記在使用的超過 50 家公司 | 文檔齊全 | 有明確的發展計劃
支持集羣部署
X-Job:集羣部署唯一要求爲:保證每個集羣節點配置(db 和登陸賬號等)保持一致。調度中心通過 db 配置區分不同集羣。
執行器支持集羣部署,提升調度系統可用性,同時提升任務處理能力。集羣部署唯一要求爲:保證集羣中每個執行器的配置項 xxl.job.admin.addresses/調度中心地址”
保持一致,執行器根據該配置進行執行器自動註冊等操作。
E-Job:重寫 Quartz 基於數據庫的分佈式功能,改用 Zookeeper 實現註冊中心
作業註冊中心:基於 Zookeeper 和其客戶端 Curator 實現的全局作業註冊控制中心。用於註冊,控制和協調分佈式作業執行。
多節點部署時任務不能重複執行
X-Job:使用 Quartz 基於數據庫的分佈式功能
E-Job:將任務拆分爲 n 個任務項後,各個服務器分別執行各自分配到的任務項。一旦有新的服務器加入集羣,或現有服務器下線,elastic-job 將在保留本次任務執行不變的情況下,下次任務開始前觸發任務重分片。
日誌可追溯
X-Job:支持,有日誌查詢界面
E-Job:可通過事件訂閱的方式處理調度過程的重要事件,用於查詢、統計和監控。Elastic-Job 目前提供了基於關係型數據庫兩種事件訂閱方式記錄事件。
監控告警
X-Job:調度失敗時,將會觸發失敗報警,如發送報警郵件。
任務調度失敗時郵件通知的郵箱地址,支持配置多郵箱地址,配置多個郵箱地址時用逗號分隔
E-Job:通過事件訂閱方式可自行實現
作業運行狀態監控、監聽作業服務器存活、監聽近期數據處理成功、數據流類型作業(可通過監聽近期數據處理成功數判斷作業流量是否正常, 如果小於作業正常處理的閥值,可選擇報警。)、監聽近期數據處理失敗(可通過監聽近期數據處理失敗數判斷作業處理結果,如果大於 0,可選擇報警。)
彈性擴容縮容
X-Job:使用 Quartz 基於數據庫的分佈式功能,服務器超出一定數量會給數據庫造成一定的壓力
E-Job:通過 zk 實現各服務的註冊、控制及協調
支持並行調度
X-Job:調度系統多線程(默認 10 個線程)觸發調度運行,確保調度精確執行,不被堵塞。
E-Job:採用任務分片方式實現。將一個任務拆分爲 n 個獨立的任務項,由分佈式的服務器並行執行各自分配到的分片項。
高可用策略
X-Job:“調度中心” 通過 DB 鎖保證集羣分佈式調度的一致性, 一次任務調度只會觸發一次執行;
E-Job:調度器的高可用是通過運行幾個指向同一個 ZooKeeper 集羣的 Elastic-Job-Cloud-Scheduler 實例來實現的。ZooKeeper 用於在當前主 Elastic-Job-Cloud-Scheduler 實例失敗的情況下執行領導者選舉。通過至少兩個調度器實例來構成集羣,集羣中只有一個調度器實例提供服務,其他實例處於” 待命” 狀態。當該實例失敗時,集羣會選舉剩餘實例中的一個來繼續提供服務。
失敗處理策略
X-Job:調度失敗時的處理策略,策略包括:失敗告警(默認)、失敗重試;
E-Job:彈性擴容縮容在下次作業運行前重分片,但本次作業執行的過程中,下線的服務器所分配的作業將不會重新被分配。失效轉移功能可以在本次作業運行中用空閒服務器抓取孤兒作業分片執行。同樣失效轉移功能也會犧牲部分性能。
動態分片策略
X-Job:分片廣播任務以執行器爲維度進行分片,支持動態擴容執行器集羣從而動態增加分片數量,協同進行業務處理;在進行大數據量業務操作時可顯著提升任務處理能力和速度。
執行器集羣部署時,任務路由策略選擇” 分片廣播” 情況下,一次任務調度將會廣播觸發對應集羣中所有執行器執行一次任務,同時傳遞分片參數;可根據分片參數開發分片任務;
E-Job:支持多種分片策略,可自定義分片策略
默認包含三種分片策略:基於平均分配算法的分片策略、 作業名的哈希值奇偶數決定 IP 升降序算法的分片策略、根據作業名的哈希值對 Job 實例列表進行輪轉的分片策略,支持自定義分片策略
elastic-job 的分片是通過 zookeeper 來實現的。分片的分片由主節點分配,如下三種情況都會觸發主節點上的分片算法執行:a、新的 Job 實例加入集羣 b、現有的 Job 實例下線(如果下線的是 leader 節點,那麼先選舉然後觸發分片算法的執行) c、主節點選舉”
和 quartz 框架對比
-
調用 API 的的方式操作任務,不人性化;
-
需要持久化業務 QuartzJobBean 到底層數據表中,系統侵入性相當嚴重。
-
調度邏輯和 QuartzJobBean 耦合在同一個項目中,這將導致一個問題,在調度任務數量逐漸增多,同時調度任務邏輯逐漸加重的情況加,此時調度系統的性能將大大受限於業務;
-
Quartz 關注點在於定時任務而非數據,並無一套根據數據處理而定製化的流程。雖然 Quartz 可以基於數據庫實現作業的高可用,但缺少分佈式並行調度的功能。
綜合對比
總結和結論
共同點:
E-Job 和 X-job 都有廣泛的用戶基礎和完整的技術文檔,都能滿足定時任務的基本功能需求。
不同點:
X-Job 側重的業務實現的簡單和管理的方便,學習成本簡單,失敗策略和路由策略豐富。推薦使用在 “用戶基數相對少,服務器數量在一定範圍內” 的情景下使用。
E-Job 關注的是數據,增加了彈性擴容和數據分片的思路,以便於更大限度的利用分佈式服務器的資源。但是學習成本相對高些,推薦在 “數據量龐大,且部署服務器數量較多” 時使用。
附定時任務的其他方案
發貨後超過 10 天未收貨時系統自動確認收貨的多種實現方式:
-
每天定時半夜篩選第二天 可以自動確認收貨的訂單, 然後第二天 每 10 分鐘 執行一次確認收貨 開銷不會太大吧 時間也相對精確
-
自動確認收貨這個狀態如果僅僅是讓客戶端看的話,等用戶下一次上線的時間,做一次運算就可以了。
-
延遲和定時消息投遞
-
ActiveMQ 提供了一種 broker 端消息定時調度機制。適用於:1、不希望消息馬上被 broker 投遞出去,而是想要消息 60 秒以後發給消費者,2、想讓消息沒隔一定時間投遞一次,一共投遞指定的次數
-
RabbitMQ 可以針對 Queue 和 Message 設置 x-message-tt,來控制消息的生存時間,如果超時,則消息變爲 dead letter。利用 DLX,當消息在一個隊列中變成死信後,它能被重新 publish 到另一個 Exchange。這時候消息就可以重新被消費。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/bcHJ2ZjKwftD9LTh1EO7cA