Cloud Native
定時任務是業務應用開發中非常普遍存在的場景(如:每分鐘掃描超時支付的訂單,每小時清理一次數據庫曆史數據,每天統計前一天的數據并生成報表等等), 解決方案很多 ,Spring 框架提供了一種通過注解來配置定時任務的解決方案,接入非常的簡單,僅需如下兩步:
1. 在啟動類上添加注解@EnableScheduling
@SpringBootApplication
@EnableScheduling // 添加定時任務啟動注解
public class SpringSchedulerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringSchedulerApplication.class, args);
}
}
2. 開發定時任務 Bean 并配置相應的定時注解@Scheduled
@Component
public class SpringScheduledProcessor {
/**
* 通過Cron表達式指定頻率或指定時間
*/
@Scheduled(cron = "0/5 * * * * ?")
public void doSomethingByCron() {
System.out.println("do something");
}
/**
* 固定執行間隔時間
*/
@Scheduled(fixedDelay = 2000)
public void doSomethingByFixedDelay() {
System.out.println("do something");
}
/**
* 固定執行觸發頻率
*/
@Scheduled(fixedRate = 2000)
public void doSomethingByFixedRate() {
System.out.println("do something");
}
}
Spring 定時任務原理
Cloud Native
運行原理Spring 定時任務核心邏輯主要在 spring-context 中的 scheduling 包中,其主要結構包括:
業務邏輯會将被包裝在 ScheduledMethodRunnable 類中,其中包含了待執行的目标業務對象 Bean 和業務方法,該 Runnable 對象在運行時會被提交至 ScheduledExecutorService 調度線程池完成任務的定時運行。
從上圖可以看到真正要運行的業務邏輯 ScheduledMethodRunnable 會被 ReschedulingRunnable、DelegatingErrorHandlingRunnable 做了代理擴展,這兩層代理擴展具有如下意義:
Spring 定時任務 Task 類的模式主要可分為兩類:IntervalTask 和 TriggerTask。前者表示固定頻率間隔執行,後者則采用 Trigger 觸發器模式實現定時調度,Cron 表達式配置為該模式實現。
默認配置下底層運行的線程池為單線程,單線程的運行模型在任務量較多且觸發頻率較高的情況下,一旦某個任務發生阻塞會導緻所有後續定時任務運行阻斷,這對業務運行帶來嚴重隐患。常見可采用如下方式:
@Scheduled(fixedDelay = 2000)
@Async
public void test() {
System.out.println(DateUtil.now() " test.");
}
定時任務運行可設置統一異常處理,基于 ErrorHandler 接口開發對應異常處理實現類。對應的異常實現處理類需要注入到核心的 ThreadPoolTaskScheduler 中,用戶可以通過自定義 TaskSchedulerCustomizer 方式來實現 ErrorHandler 自定義異常處理 Bean 注入至 ThreadPoolTaskScheduler 中。
@Component
public class DemoTaskSchedulerCustomizer implements TaskSchedulerCustomizer {
@Override
public void customize(ThreadPoolTaskScheduler taskScheduler) {
taskScheduler.setErrorHandler(new DemoErrorHandler());
}
private class DemoErrorHandler implements ErrorHandler {
@Override
public void handleError(Throwable throwable) {
System.out.println("異常統一處理.");
}
}
}
Cloud Native
任務重複執行Spring 定時任務,隻要有注解就會執行,在分布式場景下,所有機器代碼一緻,會導緻同一個任務在多台機器上重複執行。 一般的解決方案是搶鎖觸發,分布式鎖實現形式可采用 DB、ZK、Redis 等方式。
示例代碼 如下:
@Component
@EnableScheduling
public class MyTask {
/**
* 每分鐘的第30秒跑一次
*/
@Scheduled(cron = "30 * * * * ?")
public void task1() throws Exception {
String lockName = "task1";
if (tryLock(lockName)) {
System.out.println("hello cron");
releaseLock(lockName);
} else {
return;
}
}
private boolean tryLock(String lockName) {
//TODO
return true;
}
private void releaseLock(String lockName) {
//TODO
}
}
如 上圖所示,當任務觸發時 3 個 server 會對任務搶鎖,僅獲得任務鎖的 server 才能執行對應任務業務邏輯。 當前的這個設計,仔細一點的同學可以發現,其實還是有可能導緻任務重複執行的。 比如任務執行的非常快,A 這台機器搶到鎖,執行完任務後很快就釋放鎖了。 B 這台機器後搶鎖,還是會搶到鎖,再執行一遍任務。
無管控無運維原生 Spring 定時任務沒有控制台,無法動态的新增和修改定時任務,如果要修改定時任務的配置(比如每分鐘跑一次改成每小時跑一次),必須修改代碼重新發布應用。 同時原生Spring定時任務也沒有運維操作,不支持運行一次任務,任務失敗了也不支持重跑任務。
如果要自研的可視化控制台來實現整套任務可視化管控體系,需要一定的前後端研發成本和服務部署成本投入。對于需要自建的用戶而言,可參考以下需求功能進行自有平台建設:
對于完整企業級定時任務運用方案中,報警通知能力必不可少,任務跑失敗了需要及時通知到用戶,否則可能産生故障。
原生 Spring 定時任務不支持報警通知能力,如果要自研,可以參考上一章節中《異常統一處理》對任務失敗的信息進行收集,構建相應的異常處理機制(包括對接各類報警平台進行異常消息通知處理,定義異常等級和類别進行不同的通知策略),然後進行 定時任務報警通知。
定時任務在運行過程中會存在各種各樣的問題,比如: 執行失敗、執行耗時、執行卡住等,這些都需要在後期實際運維去定位快速分析。 在對應分析過程中沒有高效在線排查能力的話将遇到很多棘手的問題:
阿裡雲 Spring 定時任務企業級解決方案
Cloud Native
接下來主要講下如何利用公有雲上任務調度 SchedulerX 輕松接入基于 Spring 開發的定時任務。前面聊了基于 Spring 原生功能在使用過程中面臨的問題及需要自行處理解決的相關方案,可以看到僅針對企業級最基礎的運用場景下就需要花費較多的改造投入及相關服務後續運維投入。通過接入 SchedulerX 任務調度平台,原本 Spring 定時任務使用者可無縫且 0 改造獲得企業級運用所需能力,同時降低了自研部署運維定時服務相關組件的技術成本。
如何接入對于 SchedulerX 新用戶而言接入僅需三步(參考附件接入手冊):
# 配置表示由SchedulerX接管Spring定時任務運行
spring.schedulerx2.task.scheduling.scheduler=schedulerx
# 自動同步Spring定時任務至調度平台,無需單獨手動創建(默認不開啟)
spring.schedulerx2.task.scheduling.sync=true
提供白屏控制台可以動态新增、修改、啟用、禁用任務,支持運行一次、原地重跑、重刷數據、停止任務、标記成功等運維操作。
支持執行記錄查看、執行業務日志查詢、執行全鍊路追蹤。
SchedulerX 提供豐富的報警通知能力 ,支持短信、電話、郵件、webhook 報警,支持報警聯系人組和報警曆史,可白屏動态配置。
總結
Cloud Native
本文主要從 Spring 定時任務的運行機制進行剖析闡述,并對如何擴展框架原生能力以滿足企業級生産環境運行定時任務所需各種場景提出了相應的建議,用戶可作參考構建自己内部定時任務方案。 同時就阿裡雲上提供的任務調度服務如何接入 Spring 定時任務的運行進行講解,并簡單展示了接入後所帶來的企業級能力。 最後歡迎有定時任務業務需求用戶可先通過基礎免費額度體驗感受雲上服務帶來便捷。
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!