實(shí)現(xiàn)定時(shí)任務(wù)的六種策略
這篇文章,我們聊聊實(shí)現(xiàn)定時(shí)任務(wù)的六種策略。
圖片
1 自定義單線程
圖片
上圖中,我們啟動(dòng)一個(gè)線程,該線程無(wú)限循環(huán)執(zhí)行,每隔20毫秒執(zhí)行業(yè)務(wù)代碼。
這種方式非常簡(jiǎn)單易用,在很多中間件中得到廣泛應(yīng)用。
2 JDK ScheduledExecutorService
ScheduledExecutorService 是 Java 標(biāo)準(zhǔn)庫(kù)提供的一個(gè)用于調(diào)度定時(shí)任務(wù)的接口。它提供了一種相對(duì)簡(jiǎn)單的方式來(lái)執(zhí)行定時(shí)任務(wù),不需要引入額外的庫(kù)。
圖片
在上述例子中:
- 創(chuàng)建了一個(gè)ScheduledExecutorService 實(shí)例,它使用了一個(gè)線程池,其中包含一個(gè)線程用于執(zhí)行定時(shí)任務(wù)。
- 定義了一個(gè)簡(jiǎn)單的Runnable任務(wù),輸出當(dāng)前時(shí)間。
- 使用scheduleAtFixedRate方法安排任務(wù),指定了任務(wù)的啟動(dòng)延遲時(shí)間和執(zhí)行間隔時(shí)間。
- 主線程等待一段時(shí)間,然后關(guān)閉ScheduledExecutorService,確保定時(shí)任務(wù)不再執(zhí)行。
這是一個(gè)基本的使用例子,你可以根據(jù)需求調(diào)整延遲時(shí)間、執(zhí)行間隔、線程池大小等參數(shù)。
ScheduleExecutorService 因其簡(jiǎn)單易用且性能優(yōu)異,在各大開源中間件項(xiàng)目(比如 RocketMQ、MetaQ、Canal 等)中被廣泛的使用。
3 Spring Task
在Spring框架中,你可以使用@Scheduled注解來(lái)創(chuàng)建定時(shí)任務(wù)。以下是Spring定時(shí)任務(wù)的基本用法:
- 配置類: 創(chuàng)建一個(gè)配置類,通常使用 @EnableScheduling 注解啟用 Spring 的定時(shí)任務(wù)功能。
圖片
- 定時(shí)任務(wù)方法: 在你的服務(wù)類或組件類中創(chuàng)建一個(gè)方法,并使用 @Scheduled 注解來(lái)指定定時(shí)任務(wù)的觸發(fā)條件。
圖片
在上述例子中,@Scheduled 注解允許你指定定時(shí)任務(wù)的執(zhí)行規(guī)則,可以是固定頻率(fixedRate)、固定延遲(fixedDelay)、或者使用cron表達(dá)式。
4 Quartz
Quartz是一款 Java 開源任務(wù)調(diào)度框架。
圖片
下面我們展示如何使用:
1、添加依賴
圖片
2、Job(任務(wù):你要做什么事)
圖片
3、Trigger(觸發(fā)器:什么時(shí)候去做)
4、scheduler(任務(wù)調(diào)度:你什么時(shí)候需要做什么事)將 job 與 Trigger 進(jìn)行整合。
下面是一個(gè)例子:
圖片
這里需要強(qiáng)調(diào)的是,Quartz 支持集群模式,持久化方式是 JDBC ,需要?jiǎng)?chuàng)建如下表。
圖片
Quartz 集群模式對(duì)于業(yè)務(wù)數(shù)據(jù)庫(kù)有侵入性,需要考慮業(yè)務(wù)場(chǎng)景慎重使用。
5 elastic-job
ElasticJob 定位為輕量級(jí)無(wú)中心化解決方案,使用 jar 的形式提供分布式任務(wù)的協(xié)調(diào)服務(wù)。
圖片
應(yīng)用內(nèi)部定義任務(wù)類,實(shí)現(xiàn) SimpleJob 接口,編寫自己任務(wù)的實(shí)際業(yè)務(wù)流程即可。
圖片
舉例:應(yīng)用A有五個(gè)任務(wù)需要執(zhí)行,分別是A,B,C,D,E。任務(wù)E需要分成四個(gè)子任務(wù),應(yīng)用部署在兩臺(tái)機(jī)器上。
圖片
應(yīng)用A在啟動(dòng)后, 5個(gè)任務(wù)通過(guò) Zookeeper 協(xié)調(diào)后被分配到兩臺(tái)機(jī)器上,通過(guò)Quartz Scheduler 分開執(zhí)行不同的任務(wù)。
ElasticJob 從本質(zhì)上來(lái)講 ,底層任務(wù)調(diào)度還是通過(guò) Quartz ,相比Redis分布式鎖 或者 Quartz 分布式部署 ,它的優(yōu)勢(shì)在于可以依賴 Zookeeper 這個(gè)大殺器 ,將任務(wù)通過(guò)負(fù)載均衡算法分配給應(yīng)用內(nèi)的 Quartz Scheduler容器。
6 xxl-job
XXL-JOB 是一個(gè)使用最廣泛的分布式任務(wù)調(diào)度平臺(tái)。
業(yè)務(wù)系統(tǒng)和調(diào)度平臺(tái)分開部署,我們?cè)谡{(diào)度平臺(tái)上配置應(yīng)用以及其定時(shí)任務(wù),當(dāng)任務(wù)需要執(zhí)行時(shí),調(diào)度平臺(tái)會(huì)觸發(fā)業(yè)務(wù)系統(tǒng)的任務(wù),業(yè)務(wù)系統(tǒng)執(zhí)行完任務(wù)之后,反饋給調(diào)度平臺(tái)任務(wù)執(zhí)行的結(jié)果。
接下來(lái),我們使用 xxl-job 開發(fā)第一個(gè)任務(wù) “Hello World”。
1、新建任務(wù):
登錄調(diào)度中心,點(diǎn)擊下圖所示“新建任務(wù)”按鈕,新建示例任務(wù)。然后,參考下面截圖中任務(wù)的參數(shù)配置,點(diǎn)擊保存。
圖片
圖片
2、應(yīng)用任務(wù)開發(fā)
圖片
3、觸發(fā)執(zhí)行
請(qǐng)點(diǎn)擊任務(wù)右側(cè) “執(zhí)行” 按鈕,可手動(dòng)觸發(fā)一次任務(wù)執(zhí)行(通常情況下,通過(guò)配置Cron表達(dá)式進(jìn)行任務(wù)調(diào)度觸發(fā))。
4、查看日志
請(qǐng)點(diǎn)擊任務(wù)右側(cè) “日志” 按鈕,可前往任務(wù)日志界面查看任務(wù)日志。在任務(wù)日志界面中,可查看該任務(wù)的歷史調(diào)度記錄以及每一次調(diào)度的任務(wù)調(diào)度信息、執(zhí)行參數(shù)和執(zhí)行信息。
運(yùn)行中的任務(wù)點(diǎn)擊右側(cè)的“執(zhí)行日志”按鈕,可進(jìn)入日志控制臺(tái)查看實(shí)時(shí)執(zhí)行日志。
圖片
7 寫到最后
本文整理了實(shí)現(xiàn)定時(shí)任務(wù)的六種策略,我們需要根據(jù)實(shí)際場(chǎng)景選擇合適的策略。
同時(shí),我們也需要考慮:
- 是否需要任務(wù)應(yīng)用集群部署;
- 集群部署下假如出現(xiàn)并發(fā)執(zhí)行,業(yè)務(wù)是否會(huì)出現(xiàn)異常;
- 如何規(guī)避并發(fā)執(zhí)行導(dǎo)致的業(yè)務(wù)異常。