之前有段时间公司任务不多,领导牵头开了一个技术沙龙,一个同事就分享介绍了xxl-job;作者最近回头查阅了相关资料,在此把知识点整理出来。
xxl-job,是一款分布式轻量级的任务调度框架。它的命名也是根据它的作者:许雪里,拼音首字母而来。其核心设计目标是开发迅速、学习简单、轻量级、易扩展。当项目中碰到定时任务、批量数据处理时,技术选型可以考虑用它。
服务端
github地址:
https://github.com/xuxueli/xxl-job
下载下来后,用idea打开,可以看到项目结构:
有4个主要的文件夹:
xxl-job-admin:任务调度平台
xxl-job-core:核心代码
xxl-job-executor-samples:示例代码
doc:文档
服务端的运行依赖数据库,我们找到doc\db\tables_xxl_job.sql,执行一下,会建立对应的数据库和表。接下来到项目的xxl-job-admin\src\main\resources\application.properties中,修改数据库连接:
按照自己mysql的ip、端口、用户名、密码进行配置。日志配置也建议修改下,在xxl-job-admin/src/main/resources/logback.xml中,有一行:
<property name="log.path" value="/data/applogs/xxl-job/xxl-job-admin.log"/>
可以修改为:
<property name="log.path" value="./applogs/xxl-job/xxl-job-admin.log"/>
此时日志文件是保存在该项目下。
修改完后,我们就可以启动xxl-job-admin了。这是一个SpringBoot项目,直接运行启动类:XxlJobAdminApplication。启动好后,浏览器输入访问网址:http://localhost:8080/xxl-job-admin/toLogin,能看到登录页面,输入admin(用户名)、123456(密码),就能够访问任务调度平台了。
客户端
我们打开idea,新建一个SpringBoot项目,引入web依赖:
创建好后,再引入xxl-job的依赖:
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>2.3.0</version>
</dependency>
修改application.properties配置文件,如下:
# web port
server.port=8089
# 配置调度中心地址
xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin
# 执行器和调度中心之间的通信令牌,如果没有配置,表示关闭了通信令牌的校验
# 在xxl-job-admin的配置文件中,有一个一模一样的配置项,两边都配置,就会进行校验
xxl.job.accessToken=default_token
# 配置执行器的名字
xxl.job.executor.appname=xxl-job-demo
# 执行器地址,如果没有配置,就使用 IP:PORT 作为默认值
xxl.job.executor.address=
# 执行器 ip 地址
xxl.job.executor.ip=
# 执行器端口,默认即 9999
xxl.job.executor.port=9999
# 执行器日志文件位置
xxl.job.executor.logpath=./applogs/xxl_job/jobhandler
# 执行器日志保存时间
xxl.job.executor.logretentiondays=30
之后我们再提供一个配置类:
@Configuration
public class XxlJobConfig {
@Value("${xxl.job.admin.addresses}")
private String adminAddresses;
@Value("${xxl.job.accessToken}")
private String accessToken;
@Value("${xxl.job.executor.appname}")
private String appname;
@Value("${xxl.job.executor.address}")
private String address;
@Value("${xxl.job.executor.ip}")
private String ip;
@Value("${xxl.job.executor.port}")
private int port;
@Value("${xxl.job.executor.logpath}")
private String logPath;
@Value("${xxl.job.executor.logretentiondays}")
private int logRetentionDays;
@Bean
public XxlJobSpringExecutor xxlJobExecutor() {
XxlJobSpringExecutor xxlJobSpringExecutor =
new XxlJobSpringExecutor();
xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
xxlJobSpringExecutor.setAppname(appname);
xxlJobSpringExecutor.setAddress(address);
xxlJobSpringExecutor.setIp(ip);
xxlJobSpringExecutor.setPort(port);
xxlJobSpringExecutor.setAccessToken(accessToken);
xxlJobSpringExecutor.setLogPath(logPath);
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
return xxlJobSpringExecutor;
}
}
这个配置类会对应一个任务调度平台的执行器,我们要手动新建它:
我们还要编写定时任务的执行代码:
@Component
public class MyJob {
@XxlJob("demoJobHandler")
public ReturnT<String> demoJobHandler() throws Exception {
// 获取参数
String param = XxlJobHelper.getJobParam();
// 打印日志
XxlJobHelper.log("xxl测试: {}", param);
return ReturnT.SUCCESS;
}
}
去任务调度中心,新建对应的任务,指定该任务的相关配置(定时执行的周期、参数、路由策略等):
我们找到客户端的启动类,运行好后,能够在执行器管理页面看到变化:
任务也要去手动启动:
定时任务执行后,我们到调度任务菜单中,能看到任务执行的相关信息:
点击操作列的执行日志,能够看到打印的日志:
注:打印日志的:XxlJobHelper.log(“xxl测试: {}”, param),它只在任务调度中心中能看到,不会在idea的控制台显示的。要想在控制台打印,可以用Logback等日志框架来实现。
Cron表达式
由7个部分组成,
秒 分 时 日 月 星期 年份(可不填)
各个部分的范围:
秒:0~59 , - * /
分:0~59 , - * /
时:0~23 , - * /
日:1~31 , - * / ? L W
月:0~11 , - * /
星期:1~7 , - * / ? L #
年份:1970~2099 , - * /
,:多个匹配值用逗号隔开,如放在时部分:2,13,16表示2点、13点、16点同时匹配
-:表示范围,如放在时部分:8-12表示8、9、10、11、12时同时匹配
*:表示任意匹配,如放在秒部分:*表示每秒触发
/:开始时间/间隔时间,如放在分部分:0/5表示从0分开始每5分钟触发一次
L:为last,表示该月的最后一日、该月的最后一个星期几,如放在星期部分:6L表示该月的最后一个星期五
W:为weekday(周一到周五),表示离目标时间最近的一个工作日,如放在日部分:15W表示离本月15号最近的一个工作日
#:X#Y,表示每月第Y个星期X,如放在星期部分:5#3表示每月的第3个星期四
?:表示不确定,忽略
高级配置
路由策略
该配置是针对客户端是集群模式的,可以电脑上安装虚拟机,把客户端打成jar包上传上去并运行,本地再运行一个客户端(此时是有2个客户端的集群);任务调度中心的执行器也要修改一下,注册方式改为手动录入,机器地址配置成本机和虚拟机上客户端的地址(用,分隔)。
第一个:机器地址配置的第一个客户端单独运行任务
最后一个:机器地址配置的最后一个客户端单独运行任务
轮询:多个客户端交替运行任务
随机:多个客户端随机某个运行任务
一致性HASH:任务按照Hash算法固定选择某个客户端
最不经常使用:优先选择使用频率最低的那个客户端
最近最久未使用:优先选择最久未使用的那个客户端
故障转移:单独某个客户端运行任务,该客户端挂了时,由下一个客户端接替运行
忙碌转移:单独某个客户端运行任务,如果该客户端没有时间运行某次任务,该任务会丢给下一个客户端
分片广播:多个客户端都运行任务,即任务会被重复运行
阻塞处理策略
单机串行:调度请求进入单机执行器后,调度请求进入FIFO队列并以串行方式运行
丢弃后续调度:调度请求进入单机执行器后,发现执行器存在运行的调度服务任务,本次请求将会被丢弃并标记为失败
覆盖之前调度:调度请求进入单机执行器后,发现执行器存在运行的调度任务,将会终止运行中的调度任务并清空队列,然后运行本地调度服务