在数据平台中,每天都会有上万个任务进行流转,如何准确,实时的完成任务,是非常关键的一步。公司在发展的过程经历了azikaban->airflow->dataflow(自研airflow支持k8s)->kepler的一个过程。目前使用的调度系统任务3w+,日执行10w+。上线0事故,非常稳定的运行。
底层调度器用的是quartz,写调度系统之前肯定要了解调度器的源码。于是记录下。
Quartz是Java领域著名的开源任务调度工具。Quartz提供了极为广泛的特性如持久化任务,集群和分布式任务等,其特点如下:
- 完全由Java写成,方便集成(Spring)
- 伸缩性
- 负载均衡
- 高可用性
使用方式
我们的使用姿势是 springboot+quartz
配置文件
quartz.org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
quartz.org.quartz.threadPool.threadCount=10
quartz.org.quartz.threadPool.threadPriority=5
quartz.org.quartz.scheduler.instanceName=kepler
quartz.org.quartz.scheduler.instanceId=AUTO
quartz.org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
quartz.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
quartz.org.quartz.jobStore.useProperties=false
quartz.org.quartz.jobStore.tablePrefix=QRTZ_
quartz.org.quartz.jobStore.isClustered=true
quartz.org.quartz.jobStore.misfireThreshold=1800000
quartz.org.quartz.jobStore.clusterCheckinInterval=5000
quartz.org.quartz.jobStore.dataSource=quartzDataSource
quartz.org.quartz.dataSource.quartzDataSource.provider=hikaricp
quartz.org.quartz.dataSource.quartzDataSource.poolName=hikari-quartz
quartz.org.quartz.dataSource.quartzDataSource.driver=${
mysql.driver-class-name}
quartz.org.quartz.dataSource.quartzDataSource.URL=${
mysql.jdbc-url}
quartz.org.quartz.dataSource.quartzDataSource.user=${
mysql.username}
quartz.org.quartz.dataSource.quartzDataSource.password=${
mysql.password}
quartz.org.quartz.dataSource.quartzDataSource.maximumPoolSize=${
mysql.maximum-pool-size}
quartz.org.quartz.dataSource.quartzDataSource.connectionTestQuery=${
mysql.connection-test-query}
quartz.org.quartz.dataSource.quartzDataSource.connectionTimeout=${
mysql.connection-timeout}
quartz.org.quartz.dataSource.quartzDataSource.idleTimeout=${
mysql.idle-timeout}
quartz.org.quartz.dataSource.quartzDataSource.maxLifetime=${
mysql.max-lifetime}
Scheduler sched = SchedulerFactory.getScheduler(config);
JobDetail jobDetail = JobBuilder.newJob(jobClass)
.withIdentity(jobName, HM_JOB)//任务名称和组构成任务key
.build();
jobDetail.getJobDataMap().putAll(data);
// 触发器
SimpleTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity(jobName, HM_TRIGGER)//触发器key
.startAt(DateBuilder.futureDate(1, IntervalUnit.SECOND))
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(interval)
.repeatForever())
.build();
sched.scheduleJob(jobDetail, trigger);
// 启动
if (!sched.isShutdown()) {
sched.start();
}
工作原理
Quartz是通过对用户暴露出Scheduler来进行任务的操作,它可以把任务JobDetail和触发器Trigger加入任务池中,可以把任务删除,也可以把任务停止,scheduler把这些任务和触发器放到一个JobStore中,这里jobStore有内存形式的也有持久化形式的,当然也可以自定义扩展成独立的服务。

- Job就是自定义业务的接口,里面就一个execute方法,线程运行Job时会把JobDataMap封装到JobExecutionContext里作为execute方法的参数,jobdetail是对job的封装,里面有Job的class,对应的数据, 名称,分组等
- Trigger是触发器,job下次什么时候执行存放在trigger中
- QuartzSchedulerResources相当于调度的资源存放器,包含了JobStore, ThreadPool等资源,调度都是通过 QuartzSchedulerResources获取相关属性的。
- jobStore是任务和触发器存储地方,它里面提供大量类似于增删改的操作任务方法。
- QuartzSchedulerThread是一个调度线程,ThreadPool是一个执行线程池。里面有workerThread来执行用户任务
源码分析
根据上面的使用流程,逐个来分析源码过程
首先获取Scheluer
Scheduler scheduler = StdSchedulerFactory.getScheduler(config);
StdSchedulerFactory根据配置文件来生成Scheduler。
1.
public Scheduler getScheduler() throws SchedulerException {
//参数没传的话,则读取默认的配置
if (cfg == null) {
//初始化配置文件
initialize();
}
SchedulerRepository schedRep = SchedulerRepository.getInstance();
Scheduler sched = schedRep.lookup(getSchedulerName());
if (sched != null)
最低0.47元/天 解锁文章

8205

被折叠的 条评论
为什么被折叠?



