理论相关

概述

XXL-JOB是一个轻量级分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。xxl三个字母是其开发者许雪里名字的缩写。

几个特性:

1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手;
2、动态:支持动态修改任务状态、启动/停止任务,以及终止运行中任务,即时生效;
3、调度中心HA(中心式):调度采用中心式设计,“调度中心”自研调度组件并支持集群部署,可保证调度中心HA;
4、执行器HA(分布式):任务分布式执行,任务”执行器”支持集群部署,可保证任务执行HA;
5、注册中心: 执行器会周期性自动注册任务, 调度中心将会自动发现注册的任务并触发执行,每30秒清理一次注册表中的无效机器。同时,也支持手动录入执行器地址;
6、弹性扩容缩容:一旦有新执行器机器上线或者下线,下次调度时将会重新分配任务;
7、路由策略:执行器集群部署时提供丰富的路由策略,包括:第一个、最后一个、轮询、随机、一致性HASH、最不经常使用、最近最久未使用、故障转移、忙碌转移等;
8、故障转移:任务路由策略选择”故障转移”情况下,如果执行器集群中某一台机器故障,将会自动Failover切换到一台正常的执行器发送调度请求。
9、阻塞处理策略:调度过于密集执行器来不及处理时的处理策略,策略包括:单机串行(默认)、丢弃后续调度、覆盖之前调度;
10、任务超时控制:支持自定义任务超时时间,任务运行超时将会主动中断任务;
11、任务失败重试:支持自定义任务失败重试次数,当任务失败时将会按照预设的失败重试次数主动进行重试;其中分片任务支持分片粒度的失败重试;
12、任务失败告警;默认提供邮件方式失败告警,同时预留扩展接口,可方便的扩展短信、钉钉等告警方式;
13、分片广播任务:执行器集群部署时,任务路由策略选择”分片广播”情况下,一次任务调度将会广播触发集群中所有执行器执行一次任务,可根据分片参数开发分片任务;
14、动态分片:分片广播任务以执行器为维度进行分片,支持动态扩容执行器集群从而动态增加分片数量,协同进行业务处理;在进行大数据量业务操作时可显著提升任务处理能力和速度。
15、事件触发:除了”Cron方式”和”任务依赖方式”触发任务执行之外,支持基于事件的触发任务方式。调度中心提供触发任务单次执行的API服务,可根据业务事件灵活触发

架构

一次的完整执行流程

qte5Nj.png

1、“调度中心”向“执行器”发送http调度请求: “执行器”中接收请求的服务,实际上是一台内嵌jetty服务器,默认端口9999;
2、“执行器”执行任务逻辑;
3、“执行器”http回调“调度中心”调度结果: “调度中心”中接收回调的服务,是针对执行器开放一套API服务;

调度中心:负责管理调度信息,按照调度配置发出调度请求,自身不承担业务代码。调度系统与任务解耦,提高了系统可用性和稳定性,同时调度系统性能不再受限于任务模块;
支持可视化、简单且动态的管理调度信息,包括任务新建,更新,删除,GLUE开发和任务报警等,所有上述操作都会实时生效,同时支持监控调度结果以及执行日志,支持执行器Failover。
调度模块早期依赖于quartz,为了精简系统降低冗余依赖,和提供系统的可控度与稳定性;现在使用选择自研调度组件,类似于一个时间轮。
XXL-JOB中“调度模块”和“任务模块”完全解耦,调度模块进行任务调度时,将会解析不同的任务参数发起远程调用,调用各自的远程执行器服务。这种调用模型类似RPC调用,调度中心提供调用代理的功能,而执行器提供远程服务的功能。
执行模块:负责接收调度请求并执行任务逻辑。任务模块专注于任务的执行等操作,开发和维护更加简单和高效;接收“调度中心”的执行请求、终止请求和日志请求等;
执行器实际上是一个内嵌的Server,默认端口9999(配置项:xxl.job.executor.port)。
在项目启动时,执行器会通过“@XxlJob”识别Spring容器中“Bean模式任务”,以注解的value属性为key管理起来。
“执行器”接收到“调度中心”的调度请求时,如果任务类型为“Bean模式”,将会匹配Spring容器中的“Bean模式任务”,然后调用其execute方法,执行任务逻辑
**”bean”模式原理**:每个Bean模式任务都是一个Spring的Bean类实例,它被维护在“执行器”项目的Spring容器中。任务方法需要加“@XxlJob(value=”名称”)”注解,因为“执行器”会根据该注解识别Spring容器中的任务。

qtmPv6.png

触发

  1. 早期:基于quartz.现在:timewheel时间轮,这个时间轮本质就是一个Map<Integer, List>

  2. 触发算法:
    拿到了距now 5秒内的任务列表数据:scheduleList,分三种情况处理:for循环遍历scheduleList集合

(1)对到达now时间后的任务:(任务下一次触发时间+5s<now):直接跳过不执行; 重置trigger_next_time;

(2)对到达now时间后的任务:(任务下一次触发时间<now<任务下一次触发时间+5s):线程执行触发逻辑; 若任务下一次触发时间是在5秒内, 则放到时间轮内(Map<Integer, List> 秒数(1-60) => 任务id列表);再 重置trigger_next_time

(3)对未到达now时间的任务(任务下一次触发时间>now):直接放到时间轮内;重置trigger_next_time 。

  1. 时间轮数据结构: Map<Integer, List> key是秒数(1-60) value是任务id列表,具体结构如下图 :

qtmZUH.png

一致性保证

为了避免多个服务器同时调度任务, 通过mysql悲观锁实现分布式锁(for update语句)

1 setAutoCommit(false)关闭隐式自动提交事务

2 启动事务select lock for update(排他锁)

3 读db任务信息 -> 拉任务到内存时间轮 -> 更新db任务信息

4 commit提交事务,同时会释放for update的排他锁(悲观锁)

任务处理完毕后,释放悲观锁,准备等待下一次循环。

qtmWxx.png

Springboot整合xxljob

  1. 源码获取

    首先从GitHub上面将项目clone下来,如果网络问题导致速度慢也可以从Gitee上面拉取

    GitHub地址:https://github.com/xuxueli/xxl-job

    Gitee地址:https://gitee.com/xuxueli0323/xxl-job

    下载好之后将压缩包解压,然后通过IDEA打开,将Maven编译好后项目结构如下 xxl-job-admin 是调度中心 xxl-job-core是公共依赖 xxl-job-executor-samples 各个版本的执行器,推荐使用springboot版本
    qtnpdg.png

  2. 运行doc文件下的tables_xxl_job.sql 文件 新建了八张表

    xxl_job_lock:任务调度锁表;
    xxl_job_group:执行器信息表,维护任务执行器信息;
    xxl_job_info:调度扩展信息表: 用于保存XXL-JOB调度任务的扩展信息,如任务分组、任务名、机器地址、执行器、执行入参和报警邮件等等;
    xxl_job_log:调度日志表: 用于保存XXL-JOB任务调度的历史信息,如调度结果、执行结果、调度入参、调度机器和执行器等等;
    xxl_job_log_report:调度日志报表:用户存储XXL-JOB任务调度日志的报表,调度中心报表功能页面会用到;
    xxl_job_logglue:任务GLUE日志:用于保存GLUE更新历史,用于支持GLUE的版本回溯功能;
    xxl_job_registry:执行器注册表,维护在线的执行器和调度中心机器地址信息;
    xxl_job_user:系统用户表;
  3. 配置调度中心xxl-job-admin
    需要将其配置成自己需要的调度中心,通过该工程能够以图形化的方式统一管理任务调度平台上调度任务,负责触发调度执行。

    修改调度中心配置文件:/xxl-job/xxl-job-admin/src/main/resources/application.properties

qtnnwF.md.png

注意在数据库地址哪里加上时区属性,否则乱码

spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?Unicode=true&characterEncoding=UTF-8&serverTimezone=UTC
  1. 启动XxlJobAdminApplication类,访问http://localhost:8080/xxl-job-admin 默认账户admn,密码123456 登录后进入主页面

    qtnGy6.md.png

qtns6P.md.png

执行器管理

参数介绍:

  AppName:是每个执行器集群的唯一标示AppName, 执行器会周期性以AppName为对象进行自动注册。可通过该配置自动发现注册成功的执行器, 供任务调度时使用;

  名称:执行器的名称, 因为AppName限制字母数字等组成,可读性不强, 名称为了提高执行器的可读性;

  排序: 执行器的排序, 系统中需要执行器的地方,如任务新增, 将会按照该排序读取可用的执行器列表;

  注册方式:调度中心获取执行器地址的方式,

    自动注册:执行器自动进行执行器注册,调度中心通过底层注册表可以动态发现执行器机器地址;

    手动录入:人工手动录入执行器的地址信息,多地址逗号分隔,供调度中心使用;

  机器地址:”注册方式”为”手动录入”时有效,支持人工维护执行器的地址信息;

  1. 在源码 xxl-job-executor-samples 下springboot模块下jobhandler层下面新建一个自己的定时任务测试。 只是控制台输出,xxl-job有自己的日志打印。

qtnTXV.md.png

  1. 在任务管理里面新增任务,点击启动即可测试。执行器配置一般选择自动注册,会扫描出ip和port。

    任务管理参数

    参数介绍:

      执行器:任务的绑定的执行器,任务触发调度时将会自动发现注册成功的执行器, 实现任务自动发现功能; 另一方面也可以方便的进行任务分组。每个任务必须绑定一个执行器, 可在 “执行器管理” 进行设置。

      任务描述:任务的描述信息,便于任务管理;

      路由策略:当执行器集群部署时,提供丰富的路由策略,包括;
          FIRST(第一个):固定选择第一个机器;
          LAST(最后一个):固定选择最后一个机器;
          ROUND(轮询):;
          RANDOM(随机):随机选择在线的机器;
          CONSISTENT_HASH(一致性HASH):每个任务按照Hash算法固定选择某一台机器,且所有任务均匀散列在不同机器上。
          LEAST_FREQUENTLY_USED(最不经常使用):使用频率最低的机器优先被选举;
          LEAST_RECENTLY_USED(最近最久未使用):最久为使用的机器优先被选举;
          FAILOVER(故障转移):按照顺序依次进行心跳检测,第一个心跳检测成功的机器选定为目标执行器并发起调度;
          BUSYOVER(忙碌转移):按照顺序依次进行空闲检测,第一个空闲检测成功的机器选定为目标执行器并发起调度;
          SHARDING_BROADCAST(分片广播):广播触发对应集群中所有机器执行一次任务,同时系统自动传递分片参数;可根据分片参数开发分片任务;
      Cron:触发任务执行的Cron表达式;
      运行模式
          BEAN模式:任务以JobHandler方式维护在执行器端;需要结合 “JobHandler” 属性匹配执行器中任务;
          GLUE模式(Java):任务以源码方式维护在调度中心;该模式的任务实际上是一段继承自IJobHandler的Java类代码并 “groovy” 源码方式维护,它在执行器项目中运行,可使用       @Resource/@Autowire注入执行器里中的其他服务;
          GLUE模式(Shell):任务以源码方式维护在调度中心;该模式的任务实际上是一段 “shell” 脚本;
          GLUE模式(Python):任务以源码方式维护在调度中心;该模式的任务实际上是一段 “python” 脚本;
          GLUE模式(PHP):任务以源码方式维护在调度中心;该模式的任务实际上是一段 “php” 脚本;
          GLUE模式(NodeJS):任务以源码方式维护在调度中心;该模式的任务实际上是一段 “nodejs” 脚本;
          GLUE模式(PowerShell):任务以源码方式维护在调度中心;该模式的任务实际上是一段 “PowerShell” 脚本;
      JobHandler:运行模式为 “BEAN模式” 时生效,对应执行器中新开发的JobHandler类“@JobHandler”注解自定义的value值;
      阻塞处理策略:调度过于密集执行器来不及处理时的处理策略;
          单机串行(默认):调度请求进入单机执行器后,调度请求进入FIFO队列并以串行方式运行;
          丢弃后续调度:调度请求进入单机执行器后,发现执行器存在运行的调度任务,本次请求将会被丢弃并标记为失败;
          覆盖之前调度:调度请求进入单机执行器后,发现执行器存在运行的调度任务,将会终止运行中的调度任务并清空队列,然后运行本地调度任务;
      子任务:每个任务都拥有一个唯一的任务ID(任务ID可以从任务列表获取),当本任务执行结束并且执行成功时,将会触发子任务ID所对应的任务的一次主动调度。
      任务超时时间:支持自定义任务超时时间,任务运行超时将会主动中断任务;
      失败重试次数;支持自定义任务失败重试次数,当任务失败时将会按照预设的失败重试次数主动进行重试;
      报警邮件:任务调度失败时邮件通知的邮箱地址,支持配置多邮箱地址,配置多个邮箱地址时用逗号分隔;
      负责人:任务的负责人;
      执行参数:任务执行所需的参数,多个参数时用逗号分隔,任务执行时将会把多个参数转换成数组传入;

    1. 点击执行 启动 即可查看日志和控制台

    项目中集成xxljob

    1. 在项目中引入依赖
    <dependency>
    <groupId>com.xuxueli</groupId>
    <artifactId>xxl-job-core</artifactId>
    <version>2.0.1</version>
    </dependency>

    2.将xxl-job-executor-sample-springboot这个模块下的XxlJobConfig复制一份到项目中,然后将相关配置设置好即可

qtui7D.md.png