新四季網

spring怎麼關閉定時器(說說Spring定時任務如何大規模企業級運用)

2023-04-20 05:52:53

Spring 定時任務簡介

Cloud Native

定時任務是業務應用開發中非常普遍存在的場景(如:每分鐘掃描超時支付的訂單,每小時清理一次資料庫歷史數據,每天統計前一天的數據並生成報表等等), 解決方案很多 ,Spring 框架提供了一種通過註解來配置定時任務的解決方案,接入非常的簡單,僅需如下兩步:

1. 在啟動類上添加註解@EnableScheduling

@SpringBootApplication@EnableScheduling // 添加定時任務啟動註解public class SpringSchedulerApplication { public static void main(String[] args) { SpringApplication.run(SpringSchedulerApplication.class, args); }}

2. 開發定時任務 Bean 並配置相應的定時註解@Scheduled

@Componentpublic 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 包中,其主要結構包括:

定時任務解析:通過 ScheduledTasksBeanDefinitionParser 對 XML 定義任務配置解析;也可通過 ScheduledAnnotationBeanPostProcessor對@Scheduled 註解進行任務解析(常見模式)。定時任務註冊登記:上述解析獲得的 Task 任務配置會被註冊登記至 ScheduledTaskRegistrar 中以備運行使用。任務定時運行:完成所有任務註冊登記後,會通過 TaskScheduler 正式地定時運行相關任務,底層通過 JDK 的 ScheduledExecutorService 運行任務。

業務邏輯會將被包裝在 ScheduledMethodRunnable 類中,其中包含了待執行的目標業務對象 Bean 和業務方法,該 Runnable 對象在運行時會被提交至 ScheduledExecutorService 調度線程池完成任務的定時運行。

從上圖可以看到真正要運行的業務邏輯 ScheduledMethodRunnable 會被 ReschedulingRunnable、DelegatingErrorHandlingRunnable 做了代理擴展,這兩層代理擴展具有如下意義:

DelegatingErrorHandlingRunnable:為業務方法運行異常進行包裝處理,提供了自定義異常處理機制、解決 JDK 原生定時任務執行異常後任務失效問題。ReschedulingRunnable:提供了擴展的定時模式支持,可支持基於 Trigger 接口自定義實現獲取下次觸發時間定時調度,默認提供的 Cron 定時通過此方式進行擴展實現。定時模式

Spring 定時任務 Task 類的模式主要可分為兩類:IntervalTask 和 TriggerTask。前者表示固定頻率間隔執行,後者則採用 Trigger 觸發器模式實現定時調度,Cron 表達式配置為該模式實現。

FixedDelay:按固定延遲頻率執行,任務下一次觸發時間=上一次執行結束時間 Delay 延遲時間。

FixedRate:按固定頻率觸發執行,任務下一次觸發時間=上一次觸發時間 Delay 延遲時間。如果上一次執行方法不結束會阻塞下一次任務執行。

Cron 表達式:按 Cron 表達式計算下一次觸發時間,任務下一次觸發時間=cron(上一次執行結束時間)。進階擴展線程池運行

默認配置下底層運行的線程池為單線程,單線程的運行模型在任務量較多且觸發頻率較高的情況下,一旦某個任務發生阻塞會導致所有後續定時任務運行阻斷,這對業務運行帶來嚴重隱患。常見可採用如下方式:

配置定時執行線程池:常見基於配置 Spring Boot 配置(spring.task.scheduling.pool.size=線程數),線程數大小取決於任務數及調度頻率合理配置。配置異步任務:在 spring context 中的 scheduling 模塊下提供了@EnableAsync 和@Async,可用於開啟任務異步執行,實現定時調度線程池非阻塞運行。該模式下存在一些不足之處:異常處理需要走異步調用的 AsyncUncaughtExceptionHandler 異常處理接口實現,同步/異步定時任務異常處理機制不統一,另外異步模式增加了業務應用的線程開銷。

@Scheduled(fixedDelay = 2000)@Asyncpublic void test { System.out.println(DateUtil.now " test.");}

異常統一處理

定時任務運行可設置統一異常處理,基於 ErrorHandler 接口開發對應異常處理實現類。對應的異常實現處理類需要注入到核心的 ThreadPoolTaskScheduler 中,用戶可以通過自定義 TaskSchedulerCustomizer 方式來實現 ErrorHandler 自定義異常處理 Bean 注入至 ThreadPoolTaskScheduler 中。

@Componentpublic 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("異常統一處理."); } }}

原生 Spring 定時任務在企業中遇到的問題

Cloud Native

任務重複執行

Spring 定時任務,只要有註解就會執行,在分布式場景下,所有機器代碼一致,會導致同一個任務在多臺機器上重複執行。 一般的解決方案是搶鎖觸發,分布式鎖實現形式可採用 DB、ZK、Redis 等方式。

示例代碼 如下:

@Component@EnableSchedulingpublic 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 Boot 版 SDK 完成調度平臺接入(版本>=1.7.2,老用戶僅升級 SDK 版本即可)配置文件添加配置項,配置開啟後 Spring 定時調度器將不運行相關任務(未配置情況下,不會主動接管原 Spring 定時任務運行,在配置開啟前不會影響原本定時任務業務運行)

# 配置表示由SchedulerX接管Spring定時任務運行spring.schedulerx2.task.scheduling.scheduler=schedulerx

控制臺上在對應應用分組下創建任務配置定時觸發。也可以選擇開啟自動同步任務配置方式(可選)

# 自動同步Spring定時任務至調度平臺,無需單獨手動創建(默認不開啟)spring.schedulerx2.task.scheduling.sync=true

接入優勢白屏管控和運維

提供白屏控制臺可以動態新增、修改、啟用、禁用任務,支持運行一次、原地重跑、重刷數據、停止任務、標記成功等運維操作。

可視化在線排查問題

支持執行記錄查看、執行業務日誌查詢、執行全鏈路追蹤。

豐富的報警通知

SchedulerX 提供豐富的報警通知能力 ,支持簡訊、電話、郵件、webhook 報警,支持報警聯繫人組和報警歷史,可白屏動態配置。

其他優勢無改造成本的平臺接入方案。無需額外獨立運維調度服務平臺或其他第三方組件服務。任務運行在集群環境中具備穩定高可靠支持,規避了原生框架存在的重複執行問題,具備故障自動轉移能力。在企業內多個團隊可共享一套平臺使用,通過命名空間和應用分組實現各團隊任務配置數據隔離及環境隔離。

總結

Cloud Native

本文主要從 Spring 定時任務的運行機制進行剖析闡述,並對如何擴展框架原生能力以滿足企業級生產環境運行定時任務所需各種場景提出了相應的建議,用戶可作參考構建自己內部定時任務方案。 同時就阿里雲上提供的任務調度服務如何接入 Spring 定時任務的運行進行講解,並簡單展示了接入後所帶來的企業級能力。 最後歡迎有定時任務業務需求用戶可先通過基礎免費額度體驗感受雲上服務帶來便捷。

,
同类文章
葬禮的夢想

葬禮的夢想

夢見葬禮,我得到了這個夢想,五個要素的五個要素,水火只好,主要名字在外面,職業生涯良好,一切都應該對待他人治療誠意,由於小,吉利的冬天夢想,秋天的夢是不吉利的
找到手機是什麼意思?

找到手機是什麼意思?

找到手機是什麼意思?五次選舉的五個要素是兩名士兵的跡象。與他溝通很好。這是非常財富,它擅長運作,職業是仙人的標誌。單身男人有這個夢想,主要生活可以有人幫忙
我不怎麼想?

我不怎麼想?

我做了什麼意味著看到米飯烹飪?我得到了這個夢想,五線的主要土壤,但是Tu Ke水是錢的跡象,職業生涯更加真誠。他真誠地誠實。這是豐富的,這是夏瑞的巨星
夢想你的意思是什麼?

夢想你的意思是什麼?

你是什​​麼意思夢想的夢想?夢想,主要木材的五個要素,水的跡象,主營業務,主營業務,案子應該抓住魅力,不能疏忽,春天夢想的吉利夢想夏天的夢想不幸。詢問學者夢想
拯救夢想

拯救夢想

拯救夢想什麼意思?你夢想著拯救人嗎?拯救人們的夢想有一個現實,也有夢想的主觀想像力,請參閱週宮官方網站拯救人民夢想的詳細解釋。夢想著敵人被拯救出來
2022愛方向和生日是在[質量個性]中

2022愛方向和生日是在[質量個性]中

[救生員]有人說,在出生88天之前,胎兒已經知道哪天的出生,如何有優質的個性,將走在什麼樣的愛情之旅,將與生活生活有什么生活。今天
夢想切割剪裁

夢想切割剪裁

夢想切割剪裁什麼意思?你夢想切你的手是好的嗎?夢想切割手工切割手有一個真正的影響和反應,也有夢想的主觀想像力。請參閱官方網站夢想的細節,以削減手
夢想著親人死了

夢想著親人死了

夢想著親人死了什麼意思?你夢想夢想你的親人死嗎?夢想有一個現實的影響和反應,還有夢想的主觀想像力,請參閱夢想世界夢想死亡的親屬的詳細解釋
夢想搶劫

夢想搶劫

夢想搶劫什麼意思?你夢想搶劫嗎?夢想著搶劫有一個現實的影響和反應,也有夢想的主觀想像力,請參閱週恭吉夢官方網站的詳細解釋。夢想搶劫
夢想缺乏缺乏紊亂

夢想缺乏缺乏紊亂

夢想缺乏缺乏紊亂什麼意思?你夢想缺乏異常藥物嗎?夢想缺乏現實世界的影響和現實,還有夢想的主觀想像,請看官方網站的夢想組織缺乏異常藥物。我覺得有些東西缺失了