在清理Github的時候,發現之前寫的一個簡單的分佈式任務分發系統ClawHub/task-distribution,使用了zk的選主與隊列,調度器使用spring的ThreadPoolTaskScheduler,任務支持cron表達式。html
這讓我想起在這以前還封裝過Quartz,那時候作的是單機版超大型應用,內部須要作調度系統。java
目前在公司使用過Elastic-Job,也使用過Spring自帶調度與ZK的結合,還有公司Boss系統提供的配置版本任務調度。git
寫這篇文章主要是簡單的回憶一下Quartz與Spring的ThreadPoolTaskScheduler,還有Elastic-job。再寫一下本身對分佈式Job的思考。github
官網地址:quartz-scheduler.orgspring
maven的pom文件:架構
<dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.3.2</version> </dependency>
具體任務:dom
import org.quartz.Job; import org.quartz.JobExecutionContext; import java.time.LocalDateTime; import java.util.Random; public class HelloJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) { System.out.println(jobExecutionContext.getJobDetail().getJobDataMap().get("jobDetailJobData1")); System.out.println(jobExecutionContext.getTrigger().getJobDataMap().get("triggerJobData1")); System.out.println("HelloJob start at:" LocalDateTime.now() ", prints: Hello Job-" new Random().nextInt(100)); } }
主調度器:maven
import org.quartz.*; import org.quartz.impl.StdSchedulerFactory; import java.util.concurrent.TimeUnit; public class MainScheduler { public static void main(String[] args) throws SchedulerException, InterruptedException { // 一、建立調度器Scheduler SchedulerFactory schedulerFactory = new StdSchedulerFactory(); Scheduler scheduler = schedulerFactory.getScheduler(); // 二、建立JobDetail實例,並與PrintWordsJob類綁定(Job執行內容) JobDetail jobDetail = JobBuilder.newJob(HelloJob.class).usingJobData("jobDetailJobData1", "測試JobDetail上下文") .withIdentity("job1", "group1").build(); // 三、構建Trigger實例,每隔1s執行一次 Trigger trigger = TriggerBuilder.newTrigger().usingJobData("triggerJobData1", "測試Trigger上下文") .withIdentity("trigger1", "triggerGroup1") .startNow()//當即生效 .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(1)//每隔1s執行一次 .repeatForever()).build();//一直執行 //四、執行 scheduler.scheduleJob(jobDetail, trigger); System.out.println("--------MainScheduler start ! ------------"); scheduler.start(); //睡眠 TimeUnit.MINUTES.sleep(1); scheduler.shutdown(); System.out.println("--------MainScheduler shutdown ! ------------"); } }
通過上面三步,執行main方法,就能夠簡單的實現調度任務了,下面分別介紹出現的角色。分佈式
Job是Quartz中的任務模板,JobDetail是Job的描述,當Scheduler執行任務的時候,會根據JobDetail建立新的Job,用過以後就釋放掉。ide
觸發器,描述了任務是何時觸發執行,經常使用有SimpleTrigger、CronTrigger,cron表達式很是強大,基本上都是基於CronTrigger來作任務調度。
JobExecutionContext任務執行的上下文,JobDataMap保存上下文傳輸的數據。
上面這幅圖能夠簡單的描述Quartz核心對象之間的關係。
底層依賴於JUC的java.util.concurrent.ScheduledExecutorService。
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.scheduling.support.CronTrigger; import java.time.LocalDateTime; import java.util.Random; public class Main { public static void main(String[] args) { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.setPoolSize(10); scheduler.initialize(); scheduler.schedule(() -> { System.out.println("HelloJob start at:" LocalDateTime.now() ", prints: Hello Job-" new Random().nextInt(100)); }, new CronTrigger("0/1 * * * * ?")); } }
Elastic-Job是一個分佈式調度解決方案,由兩個相互獨立的子項目Elastic-Job-Lite和Elastic-Job-Cloud組成。 官網:elasticjob.io。
咱們使用的是輕量級的使用方案:elasticjob/elastic-job-lite
官方架構圖: 做業執行流程圖:
我也只有使用經驗,並無深刻的瞭解其原理,具體請參考官方文檔。
如今的Quartz也有集羣版本,我尚未接觸過,如今碰到的基本上都是基於Quartz的包裝,好比Elastic-Job、xxl job、azkaban。
由於如今的項目基本都爲分佈式系統,因此對於調度系統而言,單機已經不怎麼適用了。
而對於分佈式調度系統,必然也有不少要求,下面講一下個人理解:
能想到這隻有這麼多,感受Elastic-Job就很好用。