剖析xxl-job框架的任务调度及高可用机制

XXL-JOB定时任务框架包含2个部分:

  • 定时任务调度器,即:xxl-job-admin
  • 定时任务执行器,引入了xxl-job-core组件的进程,都可以作为XXL-JOB的执行器

任务执行器调度的实现机制

整体上来讲,就是在xxl-job-admin中通过调用任务执行器的HTTP接口,实现对任务执行器的调度。
具体又可以分为2个层面进行剖析,如下:

任务执行器侧:

当在项目中引入xxl-job-core组件之后,如果是在Spring容器环境中,会通过XxlJobSpringExecutor组件的afterSingletonsInstantiated()方法做如下2件事情:
第一步,解析使用了@XxlJob注解的任务执行器方法,并保存到一个HashMap结构中,Key为@XxlJob注解的value(),值为MethodJobHandler对象。
第二步,启动一个内置的http服务器(基于Netty框架实现),这样就可以确保xxl-job-admin能够通过HTTP方法调用的方式访问到任务执行器,并通过解析HTTP参数的方式找到在第一步中解析并保存起来的任务执行器方法并执行。

任务调度中心侧:

通过XxlJobScheduler实现对任务执行器数据的读取并调用,本质上是调用任务执行器暴露的HTTP方法,当同时存在多个任务执行器时,需要实现对任务执行器的调度选择,通过ExecutorRouter来实现。

高可用实现原理

xxl-job-admin的高可用通过部署多实例来实现,当部署多实例之后如何确保同时只有一个admin实例会发起调度呢?使用了MySQL数据库的悲观锁机制,详见:JobScheduleHelper.start()方法。
任务执行器的高可用也是通过部署多实例来实现,当任务执行器也部署多实例之后如何确保同时只会调度到一个执行器上呢?在xxl-job-admin是通过不同ExecutorRouter组件实现来控制的,以ExecutorRouteFirst为例,总是返回执行器列表中的第一个:

1
2
3
4
5
6
7
8
public class ExecutorRouteFirst extends ExecutorRouter {

@Override
public ReturnT<String> route(TriggerParam triggerParam, List<String> addressList){
return new ReturnT<String>(addressList.get(0)); // 总是返回执行器列表中的第一个
}

}

关于在xxl-job-admin中对任务执行器的调度控制,详见:XxlJobTrigger.processTrigger()方法。

【参考】
XXL-JOB调度中心HA及高可用方案
XXL-Job高可用集群搭建
xxl-job高可用部署
xxl-job 实现高可用
3千字带你搞懂XXL-JOB任务调度平台
MySQL的SELECT …for update