XXl-JOB 核心源码剖析,带您领略分布式调度任务的使用场景

XXL-JOB 简述

XXL-JOB 是一个分布式任务调度平台,核心特征:开发迅速学习简单轻量级易扩展开箱即用。目前已经开发源代码,可以结合自身的业务进行二次开发

定时任务的基本概念

程序为决解一个信息处理任务而预先编制的工作执行方案,这就是定时任务,核心组成如下:

  • 执行器:负责管理应用运行时环境,用于调度定时任务。
  • 任务:任务执行的流程,是一个类,具体的业务。
  • 触发器:按照某种时间规则,执行具体的调度任务。

定时任务的使用场景

日常开发中,定时任务主要分为如下两种使用场景:

时间驱动:

  • 对账单、日结
  • 营销类短信
  • 房贷短信等

数据驱动:

  • 异步数据交换
  • 数据同步

原生定时任务缺陷有哪些缺陷?

分布式技术应用的时代,原生定时任务的缺陷显得更为突出。结合传统项目与分布式微服务的架构,思考总结如下,欢迎各位大神给与补充:

  • 不支持集群多节点部署,需要自己实现避免任务重复执行的问题。
  • 不支持生命周期统一管理,如不重启服务情况下关闭、启动任务。
  • 不支持分片任务,处理有序数据时,多机器分片执行任务处理不同数据。
  • 不支持失败重试,出现异常后任务终结,不能根据状态控制任务重新执行。
  • 不支持动态调整,不重启服务的情况下修改任务的参数。
  • 没有报警机制,当任务失败后没有报警机制通知。
  • 无法统计任务数据,当任务数据量大的时候,对于任务执行情况无法高效的统计执行情况。

基于当前 XXL-JOB 我们能做什么?

  • 执行器 HA(分布式):天生支持任务分布式执行,无需自己实现。任务"执行器"支持集群部署,可保证任务执行 HA;
  • 调度中心 HA(中心式):调度中心相当于传统调度任务的触发器,调度采用中心式设计,“调度中心”自研调度组件并支持集群部署,可保证调度中心 HA;

XXL-JOB 的基础说明

XXL-JOB 官方文档

下载源码,按照 Maven 格式将源码导入 IDE,使用 Maven 进行编译即可,源码结构如下:

  • xxl-job-admin:调度中心 , 负责调度分布式多节点任务的执行工作

  • xxl-job-core:公共依赖,核心代码,调度中心以及任务客户端都依赖核心 jar

  • xxl-job-executor-samples:执行器 Sample 示例(选择合适的版本执行器,可直接使用,也可以参考其并将现有项目改造成执行器)

    • xxl-job-executor-sample-springboot:Springboot 版本,通过 Springboot 管理执行器,推荐这种方式
    • xxl-job-executor-sample-frameless:无框架版本

具体安装使用以及配置说明,仔细阅读 XXL-JOB 官方文档.md。

手把手教你解读 XXL-JOB 的核心源码以及运行原理

XXL-JOB 架构图:

在这里插入图片描述

整理的核心关系源码图,讲述了整合核心的调用流程以及关系原理:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q7V0ieKV-1617238484945)(https://note.youdao.com/yws/api/personal/file/56CA49DF454141E2A3523510EB283BFD?method=download&shareKey=a13380a25274728a8f289af08ad89ed1)]

Admin 核心代码

程序初始化启动入口:

@Component
public class XxlJobAdminConfig implements InitializingBean, DisposableBean {

    private static XxlJobAdminConfig adminConfig = null;
    public static XxlJobAdminConfig getAdminConfig() {
        return adminConfig;
    }


    // ---------------------- XxlJobScheduler ----------------------

    private XxlJobScheduler xxlJobScheduler;

    @Override
    public void afterPropertiesSet() throws Exception {
        adminConfig = this;

        xxlJobScheduler = new XxlJobScheduler();
        xxlJobScheduler.init();
    }

    @Override
    public void destroy() throws Exception {
        xxlJobScheduler.destroy();
    }

init() 核心步骤:

        1:init i18n
        2:运行注册表监视器
        3:运行管理失败的监视器(守护线程运行)
        4:运行管理丢失的监视器(守护线程运行)
        5:启动管理触发池(守护线程运行)
            fast/slow thread pool
            fast 初始化
            corePoolSize:10
            maximumPoolSize : 200
            keepAliveTime 60m
            LinkedBlockingQueue 1000
            
            slow 初始化
            corePoolSize:10
            maximumPoolSize : 100
            keepAliveTime 60m
            LinkedBlockingQueue 2000
        6:管理日志报告(守护线程运行)
        7:任务管理器(守护线程运行)

admin 初始化工作

JobRegistryMonitorHelper.getInstance().start()

保证任务执行的时候拿到的执行器列表都是运行的。

启动一个守护线程,每 30 秒查询数据库中自动注册的执行器,查询 90 秒未再次注册的执行器,删除 90 秒未再次注册的执行器 register 表,更新 group 表的 addressList。

JobRegistryMonitorHelper.getInstance().start()

启动一个线程,扫描失败日志判断是否需要重试,需要重试则执行触发器。

initRpcProvider();

初始化 RPC 服务 AdminBiz(任务回调、注册执行器、移除执行器)

JobScheduleHelper.getInstance().start();
  • scheduleThread 构建 5 秒内要执行的任务
  • ringThread 执行 5 秒内任务的触发器

触发器的工作

  • 失败次数超过 10 次的任务使用慢线程池执行
  • 查询要执行任务的详细信息
  • 根据路由策略从执行器地址列表中得到通知的地址
  • 根据通知地址初始化远程代理对象 ExecutorBiz
  • 远程调用 executorBiz.run

Excutor 执行器核心

初始化做的事情

1. 、把当前应用中所有声明了 JobHandler 注解的类放到ConcurrentMap<String, IJobHandler>

public ReturnT<String> beat()

2. 初始化 GlueFactory

根据 codeSource 获得任务实例对象,SpringGlueFactory 拿到实例并注入属性。

3. initAdminBizList()

初始化远程 AdminBiz 远程服务代理对象,并启动一个守护线程每 30s 执行一次。

this.xxlRpcProviderFactory.initConfig(NetEnum.NETTY_HTTP, SerializeEnum.HESSIAN.getSerializer(), ip, port, accessToken, XxlJobExecutor.ExecutorServiceRegistry.class, serviceRegistryParam);

4. JobLogFileCleanThread.getInstance().start();

该线程一天执行一次,清理过期文件。

5. TriggerCallbackThread

处理任务执行结果回调给调度中心。

6. initRpcProvider()

初始化执行器 RPC 服务 ExecutorBiz。

ExecutorBiz
public ReturnT<String> beat();

路由策略故障转移算法中调用的 RPC 接口。

public ReturnT<String> idleBeat(int jobId);

路由策略忙碌转移算法中调用的 RPC 接口。

public ReturnT<String> kill(int jobId);

删除某任务。

public ReturnT<LogResult> log(long logDateTim, long logId, int fromLineNum);

查看日志。

public ReturnT<String> run(TriggerParam triggerParam);

从 jobThreadRepository 获取 JobThread。

如果没有对应的 JobThread registJobThread 一个并启动,把调用参数放到 JobThread TriggerQueue 中。

JobThread

每 3 秒获取阻塞队列任务的线程。

任务执行

1. 超时执行:

FutureTask<ReturnT<String>> futureTask = new FutureTask<ReturnT<String>>(new Callable<ReturnT<String>>() {
   @Override
   public ReturnT<String> call() throws Exception {
      return handler.execute(triggerParamTmp.getExecutorParams());
   }
});
futureThread = new Thread(futureTask);
futureThread.start();

executeResult = futureTask.get(triggerParam.getExecutorTimeout(), TimeUnit.SECONDS);

2. 普通执行:

handler.execute(triggerParamTmp.getExecutorParams());

pushCallBack 任务执行完把执行结果放入回调线程的执行队列中,90 秒内没有触发 handler 的执行,则该线程停止运行。

XxlJobExecutor.removeJobThread(jobId, "excutor idel times over limit.");
public static void removeJobThread(int jobId, String removeOldReason){
    JobThread oldJobThread = jobThreadRepository.remove(jobId);
    if (oldJobThread != null) {
        oldJobThread.toStop(removeOldReason);
        oldJobThread.interrupt();
    }
}   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值