参考:
https://www.xuxueli.com/xxl-job
调度模块(调度中心):
负责管理调度信息,按照调度配置发出调度请求,自身不承担业务代码。调度系统与任务解耦,提高了系统可用性和稳定性,同时调度系统性能不再受限于任务模块;
支持可视化、简单且动态的管理调度信息,包括任务新建,更新,删除,GLUE开发和任务报警等,所有上述操作都会实时生效,同时支持监控调度结果以及执行日志,支持执行器Failover。
执行模块(执行器):
负责接收调度请求并执行任务逻辑。任务模块专注于任务的执行等操作,开发和维护更加简单和高效;
接收“调度中心”的执行请求、终止请求和日志请求等。
源码仓库地址
源码仓库地址 | Release Download |
---|---|
https://github.com/xuxueli/xxl-job | Download |
https://gitee.com/xuxueli0323/xxl-job | Download |
中央仓库地址
<dependency>
<groupId>com.xuxueligroupId>
<artifactId>xxl-job-coreartifactId>
<version>${最新稳定版本}version>
dependency>
源码目录
- /doc :文档资料
- /db :“调度数据库”建表脚本
- /xxl-job-admin :调度中心,项目源码
- /xxl-job-core :公共Jar依赖
- /xxl-job-executor-samples :执行器,Sample示例项目(大家可以在该项目上进行开发,也可以将现有项目改造生成执行器项目)
调度中心数据库
- 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:系统用户表;
(1)初始调度数据库
db脚本位置:
xxl-job/doc/db/tables_xxl_job.sql
(2)修改调度中心配置
配置文件位置:
xxl-job/xxl-job-admin/src/main/resources/application.properties
修改db连接为第(1)步中导入的数据库,
修改报警邮箱设置,TODO
(3)启动调度中心
编译通过后可直接运行项目
xxl-job/xxl-job-admin/src/main/java/com/xxl/job/admin/XxlJobAdminApplication.java
调度中心访问地址:
http://localhost:8080/xxl-job-admin
(该地址执行器将会使用到,作为回调地址)
默认登录账号:
admin / 123456
以上示例均基于SpringBoot环境,
<dependency>
<groupId>com.xuxueligroupId>
<artifactId>xxl-job-coreartifactId>
<version>2.3.0version>
dependency>
执行器端配置文件说明
### 调度中心部署跟地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册;
xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin
### 执行器通讯TOKEN [选填]:非空时启用;
xxl.job.accessToken=
### 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册
xxl.job.executor.appname=xxl-job-executor-sample
### 执行器注册 [选填]:优先使用该配置作为注册地址,为空时使用内嵌服务 ”IP:PORT“ 作为注册地址。从而更灵活的支持容器类型执行器动态IP和动态映射端口问题。
xxl.job.executor.address=
### 执行器IP [选填]:默认为空表示自动获取IP,多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯实用;地址信息用于 "执行器注册" 和 "调度中心请求并触发任务";
xxl.job.executor.ip=
### 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;
xxl.job.executor.port=9999
### 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径;
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
### 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能;
xxl.job.executor.logretentiondays=30
注:
xxl.job.admin.addresses即对应调度中心
地址,
xxl.job.executor.appname即对应执行器名称
,
一个调度中心
可对应多个执行器名称
,
同一执行器名称
可对应多个执行器运行实例
,
同一执行器运行实例
可对应多个任务
,
调度中心根据执行器名称动态发现不同执行器集群
的在线执行器运行实例列表,
进而在同一执行器名称下的不同运行实例间进行任务路由
。
@Bean
public XxlJobSpringExecutor xxlJobExecutor() {
logger.info(">>>>>>>>>>> xxl-job config init.");
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
xxlJobSpringExecutor.setAppname(appname);
xxlJobSpringExecutor.setIp(ip);
xxlJobSpringExecutor.setPort(port);
xxlJobSpringExecutor.setAccessToken(accessToken);
xxlJobSpringExecutor.setLogPath(logPath);
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
return xxlJobSpringExecutor;
}
任务以JobHandler方式维护在执行器端,即
执行器代码工程
,程序代码编写任务
(类形式IJobHandler、方法形式@XxlJob)启动执行器工程
后,再在调度中心
控制台界面新建对应的执行器
(执行器名称同xxl.job.executor.appname
配置)调度中心
控制台界面新建对应的任务
(通过执行器、JobHandler进行关联)//BEAN模式(类形式) - 实现IJobHandler
class MyJobHandler implements IJobHandler {
/**
* execute handler, invoked when executor receives a scheduling request
*
* @throws Exception
*/
public void execute() throws Exception;
/**
* init handler, invoked when JobThread init
*/
public void init() throws Exception {
// do something
}
/**
* destroy handler, invoked when JobThread destroy
*/
public void destroy() throws Exception {
// do something
}
}
//BEAN模式(方法形式) - 为Job方法添加注解
@XxlJob(value="自定义jobhandler名称", init = "JobHandler初始化方法", destroy = "JobHandler销毁方法")
@XxlJob("demoJobHandler")
public void demoJobHandler() throws Exception {
XxlJobHelper.log("XXL-JOB, Hello World.");
}
//打印job日志,可通过调度中心控制台查看日志
XxlJobHelper.log("hello {}", "world");
//获取在调度中心控制台上设置的任务参数,
//字符串形式,由执行器端自己处理格式(如Json反序列化)
String jobParam = XxlJobHelper.getJobParam();
//借助任务参数,可实现诸如
//1. 通用HTTP任务Handler,参考SampleXxlJob.httpJobHandler
//2. 通用命令行Handler,参考SampleXxlJob.commandJobHandler
//获取分片参数
//shardIndex:当前分片序号(从0开始),执行器集群列表中当前执行器的序号;
//shardTotal:总分片数,执行器集群的总机器数量;
int shardIndex = XxlJobHelper.getShardIndex();
int shardTotal = XxlJobHelper.getShardTotal();
//自主设置任务结果(默认不设置则表示成功)
XxlJobHelper.handleFail();
XxlJobHelper.handleFail(handleMsg);
XxlJobHelper.handleSuccess();
XxlJobHelper.handleSuccess(handleMsg);
其中需要注意:
运行模式
选择BEAN
,
JobHandler
即对应@XxlJob(value="jobhandler名称
")注解中的value值,
新建任务的配置属性详细说明如下:
`基础配置`:
"执行器":任务的绑定的执行器,任务触发调度时将会自动发现注册成功的执行器, 实现任务自动发现功能; 另一方面也可以方便的进行任务分组。每个任务必须绑定一个执行器, 可在 : 执行器管理: 进行设置;
"任务描述":任务的描述信息,便于任务管理;
"负责人":任务的负责人;
"报警邮件":任务调度失败时邮件通知的邮箱地址,支持配置多邮箱地址,配置多个邮箱地址时用逗号分隔;
`触发配置`:
"调度类型":
无:该类型不会主动触发调度;
CRON:该类型将会通过CRON,触发任务调度;
固定速度:该类型将会以固定速度,触发任务调度;按照固定的间隔时间,周期性触发;
固定延迟:该类型将会以固定延迟,触发任务调度;按照固定的延迟时间,从上次调度结束后开始计算延迟时间,到达延迟时间后触发下次调度;
"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值;
"执行参数":任务执行所需的参数;
`高级配置`:
"路由策略":当执行器集群部署时,提供丰富的路由策略,包括;
FIRST(第一个):固定选择第一个机器;
LAST(最后一个):固定选择最后一个机器;
ROUND(轮询):;
RANDOM(随机):随机选择在线的机器;
CONSISTENT_HASH(一致性HASH):每个任务按照Hash算法固定选择某一台机器,且所有任务均匀散列在不同机器上。
LEAST_FREQUENTLY_USED(最不经常使用):使用频率最低的机器优先被选举;
LEAST_RECENTLY_USED(最近最久未使用):最久未使用的机器优先被选举;
FAILOVER(故障转移):按照顺序依次进行心跳检测,第一个心跳检测成功的机器选定为目标执行器并发起调度;
BUSYOVER(忙碌转移):按照顺序依次进行空闲检测,第一个空闲检测成功的机器选定为目标执行器并发起调度;
SHARDING_BROADCAST(分片广播):广播触发对应集群中所有机器执行一次任务,同时系统自动传递分片参数;可根据分片参数开发分片任务;
"子任务":每个任务都拥有一个唯一的任务ID(任务ID可以从任务列表获取),当本任务执行结束并且执行成功时,将会触发子任务ID所对应的任务的一次主动调度。
"调度过期策":
忽略:调度过期后,忽略过期的任务,从当前时间开始重新计算下次触发时间;
立即执行一次:调度过期后,立即执行一次,并从当前时间开始重新计算下次触发时间;
"阻塞处理策略":调度过于密集执行器来不及处理时的处理策略;
单机串行(默认):调度请求进入单机执行器后,调度请求进入FIFO队列并以串行方式运行;
丢弃后续调度:调度请求进入单机执行器后,发现执行器存在运行的调度任务,本次请求将会被丢弃并标记为失败;
覆盖之前调度:调度请求进入单机执行器后,发现执行器存在运行的调度任务,将会终止运行中的调度任务并清空队列,然后运行本地调度任务;
"任务超时时间":支持自定义任务超时时间,任务运行超时将会主动中断任务;
"失败重试次数":支持自定义任务失败重试次数,当任务失败时将会按照预设的失败重试次数主动进行重试;
任务以源码
方式维护在调度中心
,支持通过Web IDE在线更新
,实时编译和生效,因此不需要指定JobHandler,
支持Java(extends IJobHandler)、Shell脚本(#!/bin/bash)、Python脚本(#!/usr/bin/python)、NodeJS、PHP、PowerShell。
以GLUE模式(Java)为例进行说明。
选中新创建的GLUE(Java)任务的操作->CLUE IDE,如下图
点击GLUE IDE按钮后即弹出如下在线编辑界面,可直接在这编辑代码(也可以在IDE中开发完成后,复制粘贴到这里)。
编辑完成后点击右上角保持,会提示输入源码备注,该备注可用于标识不同版本,方便后续版本回溯。
需要注意的时,GLUE(Java)模式需要注意如下几点:
不需指定jobHandler
;extends IJobHandler
并实现逻辑;支持@Autowired/@Resource
注入执行器里中的其他服务(SpringBoot环境);关于调度中心的更多操作,
如任务管理(启停、执行一次…)、
调度日志(备注、清理、执行日志、终止任务
)、
执行器管理(手动|自动)…),
可参见官方文档: https://www.xuxueli.com/xxl-job/
基于数据库的集群方案,数据库选用Mysql;
“调度中心”通过DB锁(select * from xxl_job_lock where lock_name = 'schedule_lock' for update)
保证集群分布式调度的一致性,
假设同时存在调度中心A, B, C,
不同的调度中心在同一时刻仅有唯一的调度中心会获取到DB锁,
假如A获取锁成功,且A仅查询获取锁之后5秒内待触发的任务,
而其他调度中心B, C在获取锁的过程中会被阻塞,直到之前获取锁的调度中心A释放锁,
在A执行完调度释放锁后,其他的调度中心才可获取锁成功,
假如B成功获取锁(同样阻塞A, C),且B仅查询获取锁之后5秒内待触发的任务,
即通过DB锁来保证同一时刻仅有一个调度中心执行触发,且每次获取锁的调度中心会去触发不同时间段(拥有锁之后的5秒内)的任务。
具体细节可参见源码:com/xxl/job/admin/core/thread/JobScheduleHelper.start()
调度采用线程池方式实现,避免单线程因阻塞而引起任务调度延迟。
异步调度:调度中心每次任务触发时仅发送一次调度请求,该调度请求首先推送异步调度队列
,然后异步推送给远程执行器
异步执行:执行器会将请求存入异步执行队列
并且立即响应调度中心,异步运行。
在全异步化的基础上,调度中心中单个JOB一次调度平均耗时基本在 10ms
之内(基本为一次请求的网络开销);
因此,可以保证使用有限的线程支撑大量的JOB并发运行,
理论上默认配置下的调度中心,单机能够支撑 5000 任务
并发运行稳定运行;
## 调度线程池最大线程配置【必填】
xxl.job.triggerpool.fast.max=200
# 同一任务一分钟内超过10次调度开销在500ms以上,则使用slow线程池调度
xxl.job.triggerpool.slow.max=100
实际场景中,由于调度中心与执行器网络ping延迟不同、DB读写耗时不同、任务调度密集程度不同,会导致任务量上限会上下波动。
如若需要支撑更多的任务量,可以通过 “调大调度线程数” 、”降低调度中心与执行器ping延迟” 和 “提升机器配置” 几种方式优化。
XXL-JOB调度模块默认采用并行机制,在多线程调度的情况下,调度模块被阻塞的几率很低,大大提高了调度系统的承载量。
XXL-JOB的不同任务(即不同jobHandler)
之间并行调度、并行执行
。
XXL-JOB的单个任务(相同jobHandler)
,
针对多个执行器
是并行
运行的,
针对单个执行器
是串行
执行的。
同时支持任务终止
。
关于任务终止详细参见:https://www.xuxueli.com/xxl-job#4.9 终止运行中的任务
参考:
进击的微服务实战派—上海站 > 分布式任务调度平台 XXL-JOB