定時任務作為一種按照約定時間執行預期邏輯的通用模式,在企業級開發中承載著豐富的業務場景,諸如后臺定時同步資料生成報表,定時清理磁盤日志檔案,定時掃描超時訂單進行補償回呼等,程式開發人員在定時任務領域有著諸多框架和方案可供選擇,并借此快速實作業務功能實作產品上線,本文將就當前主流定時任務解決方案進行介紹和分析,期望可以在企業技術選型和專案架構重構時作為參考,
Crontab
目標定位
Crontab作為Linux內置的可執行命令,可以實作按照cron運算式生成的時間執行指定的系統指令或 shell腳本,
使用方式
crontab 命令語法:
crontab [-u username] [-l | -e | -r ]
引數:
-u : 只有root用戶才能進行這個任務,編輯某個用戶的crontab
-e : 編輯 crontab 的作業內容
-l : 查閱 crontab 的作業內容
-r : 移除所有的 crontab 的作業內容
組態檔示例:
* * * * * touch ~/crontab_test
* 3 * * * ~/backup
0 */2 * * * /sbin/service httpd restart
實作原理
crond守護行程是通過Linux啟動時的init行程啟動,由cornd每分鐘會檢查/etc/crontab組態檔中是否有需要執行的任務,并通過 /var/log/cron檔案輸出定時任務的執行情況,用戶可以使用Crontab命令管理/etc/crontab組態檔,
方案分析
借助Crontab用戶可以十分便利的快速實作簡易的定時任務功能,但存在以下痛點:
- 定時任務與指定linux機器系結,當機器擴容或者更換時需要重新配置contab,同時存在單點故障風險
- 隨著定時任務規模增多,無統一視角對其進行任務進度的追蹤和管控,難以維護
- 功能過于簡單,沒有超時,重試,阻塞等任務高級特性
- 可觀測能力差,問題排查定位困難
- 任務常駐,當無任務執行時造成不必要的資源成本浪費
Spring Task
目標定位
Spring框架提供了開箱即用的定時調度功能,用戶可以通過xml或者@Scheduled注解的方式標識指定方法執行的周期,Spring Task支持多種任務執行模式,包括帶時區配置的corn,固定延遲,固定速率等,
使用方式
代碼實體如下:
@EnableScheduling
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
@Component
public class MyTask {
@Scheduled(cron = "0 0 1 * * *")
public void test() {
System.out.println("test");
}
}
實作原理
Spring Task的原理是在初始化bean時借助ScheduledAnnotationBeanPostProcessor攔截@Scheduled注解所標識的方法,并根據每個方法及其注解配置構建相應的Task實體注冊到ScheduledTaskRegistrar中,并在單例bean初始化完成后通過afterSingletonsInstantiated回呼設定ScheduledTaskRegistrar中的調度器TaskScheduler,其底層依賴于jdk并發包中的ScheduledThreadPoolExecutor實作,并在afterPropertiesSet時將所有Task添加到TaskScheduler中調度執行,
方案分析
借助Spring Task用戶可以通過注解快速實作對指定方法的周期性執行,支持多種周期性策略,但與crontab相似,同樣有如下的痛點:
- 默認為單執行緒執行,若前一個任務執行時間較長會導致后續任饑餓阻塞,需要用戶自行配置執行緒池
- 各個節點獨立運行,存在單點風險,無分布式協調機制,要考慮禁止并發執行
- 隨著定時任務規模增多,無統一視角對其進行任務進度的追蹤和管控,難以維護
- 功能過于簡單,沒有超時,重試,阻塞等任務高級特性
- 可觀測能力差,問題排查定位困難
- 任務常駐,當無任務執行時造成不必要的資源成本浪費
ElasticJob
目標定位
ElasticJob作為當當網開源的一款分布式任務框架,提供彈性調度,資源管控,作業治理等諸多特性,其已經成為Apache Shardingsphere的子專案,ElasticJob目前由 2 個相互獨立的子專案 ElasticJob-Lite 和 ElasticJob-Cloud 組成,ElasticJob-Lite 定位為輕量級無中心化解決方案,使用jar的形式提供分布式任務的協調服務;ElasticJob-Cloud 使用 Mesos 的解決方案,額外提供資源治理、應用分發以及行程隔離等服務,一般使用 ElasticJob-Lite即可滿足需求,
使用方式
使用者需要在yaml中配置注冊中心zk的地址以及任務的配置資訊
elasticjob:
regCenter:
serverLists: localhost:6181
namespace: elasticjob-lite-springboot
jobs:
simpleJob:
elasticJobClass: org.apache.shardingsphere.elasticjob.lite.example.job.SpringBootSimpleJob
cron: 0/5 * * * * ?
timeZone: GMT+08:00
shardingTotalCount: 3
shardingItemParameters: 0=Beijing,1=Shanghai,2=Guangzhou
實作對應的介面即可標識對應的任務,同時通過配置監聽器來實作任務執行前后回呼:
public class MyElasticJob implements SimpleJob {
@Override
public void execute(ShardingContext context) {
switch (context.getShardingItem()) {
case 0:
// do something by sharding item 0
break;
case 1:
// do something by sharding item 1
break;
case 2:
// do something by sharding item 2
break;
// case n: ...
}
}
}
public class MyJobListener implements ElasticJobListener {
@Override
public void beforeJobExecuted(ShardingContexts shardingContexts) {
// do something ...
}
@Override
public void afterJobExecuted(ShardingContexts shardingContexts) {
// do something ...
}
@Override
public String getType() {
return "simpleJobListener";
}
}
實作原理
ElasticJob底層時間調度基于Quartz,Quartz需要持久化業務Bean到底層資料表中,系統侵入性相當嚴重,同時通過db鎖進行任務搶占,不支持并行調度,不具備可擴展性,而ElasticJob通過資料分片以及自定義分片引數的特性完成了水平擴展,可以將一個任務拆分為N個獨立的任務項,由分布式的服務器并行執行各自分配到的分片項,比如一個資料庫中有1億條資料,需要將這些資料讀取出來并進行計算,就可以將這1億條資料劃分成10個分片,每一個分片讀取其中的1千萬條資料,然后計算后寫入資料庫,如果有三臺機器執行,A機器分到分片(0,1,2,9),B機器分到分片(3,4,5),C機器分到分片(6,7,8),這也是相比于Quartz最顯著的優勢,
實作上ElasticJob使用zookeeper作為注冊中心進行分布式調度協調以及leader節點的選舉,通過注冊中心的臨時節點的變化來感知服務器的增減,每當leader節點選舉,服務器上下線,分片總數變更時均會觸發后續的重新分片,由leader節點在下次定時任務觸發時進行具體的分片劃分,再由各節點從注冊中心中獲取分片資訊,作為任務的運行引數進行執行,

方案分析
ElasticJob作為分布式任務框架,解決了上述單節點任務無法保證任務執行程序中的高可用和高并發下執行的性能的問題,并支持失敗轉移(failover)和錯過執行的作業重新執行(misfire)等高級機制,但在使用程序中仍存在以下痛點:
- 框架整體較重,需要依賴外置注冊中心zk,增加了至少三臺服務器的使用成本和維護復雜度
- 隨著任務量的不斷增多,zk作為有狀態中間件將會成為性能瓶頸
- 可觀測能力弱,需要額外引入db并配置事件追蹤
- 任務常駐,當無任務執行時造成不必要的資源成本浪費
XXLJob
目標定位
XXLJob作為大眾點評員工開源的一款分布式任務框架,其核心設計目標是開發迅速、學習簡單、輕量級、易擴展,XXLjob具備豐富的功能,如任務分片廣播,超時控制,失敗重試,阻塞策略等,并通過體驗友好的白屏化控制臺對任務進行管理和維護,
使用方式
XXLjob分為中心式調度器和分布式執行器兩部分組成,在使用時需要分別啟動,在調度中心啟動時需要配置所依賴的db配置,
執行器需要配置調度中心的地址:
xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin
xxl.job.accessToken=
xxl.job.executor.appname=xxl-job-executor-sample
xxl.job.executor.address=
xxl.job.executor.ip=
xxl.job.executor.port=9999
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
xxl.job.executor.logretentiondays=30
通過bean模式方法形式創建任務和前后回呼的使用方式如下:
@XxlJob(value = "https://www.cnblogs.com/Serverless/p/demoJobHandler2", init = "init", destroy = "destroy")
public void demoJobHandler() throws Exception {
int shardIndex = XxlJobHelper.getShardIndex();
int shardTotal = XxlJobHelper.getShardTotal();
XxlJobHelper.log("分片引數:當前分片序號 = {}, 總分片數 = {}", shardIndex, shardTotal);
}
public void init(){
logger.info("init");
}
public void destroy(){
logger.info("destory");
}
創建任務完成后,需要在控制臺上配置任務的執行策略:

實作原理
XXLJob實作上將調度系統與任務解耦,其自研調度器負責管理調度資訊,按照調度配置發出調度請求,支持可視化、簡單且動態的管理調度資訊,自動發現和路由,調度過期策略,重試策略,支持執行器Failover,執行器負責接收調度請求并執行任務邏輯,并接收任務終止請求和日志請求,負責任務超時,阻塞策略等,調度器和執行器通過restful api進行通信,調度器本身無狀態支持集群部署,提升調度系統容災和可用性,通過mysql維護鎖資訊和持久化,執行器無狀態支持集群部署,提升調度系統可用性,同時提升任務處理能力,
XXLJob一次完整的任務調度通訊流程:首先調度中心向執行器內嵌Server發送http調度請求,然后執行器執行對應的任務邏輯,待任務執行完成或超時后執行器發送http回呼向調度中心回傳呼度結果,

方案分析
XXLJob在開源社區廣泛流行,憑借其簡單的操作和豐富的功能已在多家公司投入使用,可以較好的滿足生產級別的需求,但下面的一些痛點需要改進:
- 需要依賴外置DB,增加了資料庫的使用成本和維護復雜度
- 依賴DB鎖保證集群分布式調度的一致性,當短時任務量不斷增多將對db造成較大壓力,成為性能瓶頸
- 相較于無中心模式需要額外部署調度器,調度器和執行器均需要常駐同時為保證高可用均至少兩臺,當無任務執行時造成不必要的資源成本浪費
Serverless Job
目標定位
Serverless作為云計算的最佳實踐和未來演進趨勢,其全托管免運維的使用體驗和按量付費的成本優勢使得其在云原生時代備受推崇,SAE (Serverless 應用引擎)Job 作為首款面向任務的 Serverless PaaS 平臺,提供傳統的用戶體驗,當前聚焦支持單機、廣播、并行分片模型的任務,同時支持事件驅動、并發策略和超時重試等諸多特性,提供低成本、多規格、高彈性的資源實體來滿足短時任務的執行,

使用方式
對于使用上述所有方案的存量應用,SAE (Serverless 應用引擎) Job 在兼容功能體驗的同時支持零改造無感遷移,無論用戶使用的是Crontab,Spring Task,還是ElasticJob, XXLJob,均可將代碼包或者鏡像直接部署到SAE (Serverless 應用引擎) Job中,直接升級成為Serverless架構, 從而即刻擁有Serverless所帶來的技術上的優勢,節省資源成本和運維成本,
對于運完即停的程式,無論是Java,還是Shell, Python,Go, Php均可以直接部署到SAE (Serverless 應用引擎) Job 中, 從而即刻擁有白屏化管控,全托管免運維的完備體驗以及開箱即用的可觀測功能,
實作原理
SAE (Serverless 應用引擎)Job 底層為多租Kubernetes,使用神龍裸金屬安全容器、VK對接ECI兩種方式提供集群計算資源,用戶在SAE(Serverless 應用引擎)中運行的任務會映射到Kubernetes中相應的資源,其中多租能力是借助系統隔離、資料隔離、服務隔離和網路隔離實作租戶間的隔離,SAE (Serverless 應用引擎)Job 通過Event Bridge作為事件驅動源,在支持豐富呼叫方式的同時避免了Kubernetes內置定時器不保證準時觸發以及精度時區上的問題,同時不斷完善Job控制器的企業級特性,新增自定義分片,注入配置,差異化GC, sidecar主動退出,實時日志持久化,事件通知等機制,并借助Java 位元組碼增強技術接管任務調度,實作通用的Java目標框架的零改造Serverless化,使用KubeVela軟體交付平臺作為任務發布和管理的載體,以任務為中心,以開源開放的標準,通過宣告式的方式完成整個云原生交付,SAE (Serverless 應用引擎)Job將持續優化etcd以及調度器在短時任務高并發創建場景下的效率以及實體啟動的極致彈性能力,結合彈性資源池保證任務調度的低延遲和高可用,
方案分析
SAE (Serverless 應用引擎)Job解決了上述定時任務解決方案的各種痛點,用戶無需關注任務的調度和集群資源,無需部署的額外的運維依賴組件,也無需自建一整套監控告警系統,同時更重要的是無需云主機7*24h常駐,在低資源利用率的環境下持續消耗閑置資源,
SAE (Serverless 應用引擎)Job 相較于傳統定時任務解決方案提供了三大核心價值:
- 完備全托管:提供了一站式全托管的管理界面,其任務生命周期管理、可觀測性開箱即用,用戶可以低心智負擔、零成本地學習使用 SAE (Serverless 應用引擎),
- 簡單免運維:屏蔽了底層資源,用戶只需關注其核心的業務邏輯開發,無需操心集群可用性、容量、性能等方面的問題,
- 超高性價比:采用按需使用、按量付費的模式,只有任務執行業務邏輯時才會拉起收費,其余時間不收取任何費用,極大節省了資源的成本開銷,
總結
本文對主流定時任務解決方案(Crontab, Spring Task, ElasticJob, XXLJob, Serverless Job)的目標定位,使用方式,實作原理進行了闡述,同時就企業密切關注的功能體驗,性能成本
更多內容關注 Serverless 微信公眾號(ID:serverlessdevs),匯集 Serverless 技術最全內容,定期舉辦 Serverless 活動、直播,用戶最佳實踐,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/500771.html
標籤:其他
上一篇:圖論-虛擬節點分層建圖
