【Java】SpringBoot整合xxl-job学习使用详解
文章目录
介绍
Xxl-Job是一款优秀的开源调度平台,用于管理和调度各种类型的任务,报告定时任务、分布式任务。
作用
分布式任务调度:XXL-JOB允许您在分布式环境中调度任务,这些任务可以在不同的节点上执行。它通过分布式协调和管理任务的执行,确保任务按计划运行。
Web界面:XXL-JOB提供了一个易于使用的Web界面,用于管理任务、查看任务执行日志、监控任务状态等。用户可以通过Web界面方便地创建、编辑和删除任务。
任务类型:XXL-JOB支持多种任务类型,包括定时任务(Cron表达式)、Bean任务(Java类方法)、分片任务(适用于数据分片处理)、流程任务(执行多个任务步骤的工作流程)等。
动态任务调度:XXL-JOB允许在运行时动态添加、修改和删除任务,而无需停止整个应用程序。这使得任务调度非常灵活。
任务依赖关系:您可以定义任务之间的依赖关系,确保某个任务在另一个任务成功执行后才能运行。
任务执行器:任务可以在不同的执行器上运行,例如Java、Shell、Python等。这样可以根据任务的类型和需求选择合适的执行器。
分片任务支持:XXL-JOB提供了分片任务的支持,允许将大任务分成多个小任务,每个小任务在不同的节点上并行执行,从而提高任务的执行效率。
任务日志:任务执行的日志可以在Web界面中查看,帮助用户跟踪任务的执行情况,排查问题。
报警和通知:XXL-JOB支持任务执行失败时发送报警通知,以及成功或失败后发送通知邮件。
权限管理:XXL-JOB提供了角色和权限管理功能,可以限制用户对任务调度的访问和操作。
历史任务记录:平台会保留任务执行的历史记录,用户可以随时查看历史任务的状态和日志。
集成和扩展性:XXL-JOB可以与Spring、Spring Boot、Quartz等框架集成,并提供了RESTful API,以便与其他系统进行集成。
高可用性和容错性:XXL-JOB的分布式架构支持高可用性和容错性,当某个节点出现故障时,任务可以在其他可用节点上执行。
开源和社区支持:XXL-JOB是一个开源项目,拥有活跃的社区支持,用户可以参与贡献和获取帮助。
如何使用
下载项目
可以科学上网的可以去github上clone项目,我这里是用的国内的码云进行下载项目。
我们可以从目录结构可以看出有以下三个项目子模块。
xxl-job-admin:
这个是xxl-job调度中心,这里我们不得不提一下,xxl-job其实本质是一个调度中心+执行器组成的一个框架。xxl-job本身不关注具体业务,它只负责调度。执行器启动之后要注册到调度中心,由调度中心配置具体的动作最后通信到指定的执行器上去执行具体的Handler。所以这里我们得把xxl-job-admin
项目配置好启动起来,相当于一个中台了。
xxl-job-core
: 这个应该就是xxl-job的核心源码,后续直接使用依赖直接注入就可以。要么你也可以打包,maven中央仓库应该有这个打包好的。
xxl-job-executor-samples
:这个是xxl-job的执行样例,可以看这个上面的例子来实践,告诉你客户端的具体代码如何去写,然后调度中心就可以执行到具体的业务代码上。
中央仓库地址
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>${最新稳定版本}</version>
</dependency>
这里是用的最新的2.4.0
环境
- Maven3+
- Jdk1.8+
- Mysql5.7+
调度中心
初始化“调度数据库”
请下载项目源码并解压,获取 “调度数据库初始化SQL脚本” 并执行即可。
“调度数据库初始化SQL脚本” 位置为:
/xxl-job/doc/db/tables_xxl_job.sql
调度中心支持集群部署,集群情况下各节点务必连接同一个mysql实例;
如果mysql做主从,调度中心集群节点务必强制走主库;
配置部署“调度中心”
调度中心配置文件地址:
/xxl-job/xxl-job-admin/src/main/resources/application.properties
调度中心配置内容说明:
### 调度中心JDBC链接:链接地址请保持和 2.1章节 所创建的调度数据库的地址一致
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root_pwd
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
### 报警邮箱
spring.mail.host=smtp.qq.com
spring.mail.port=25
spring.mail.username=xxx@qq.com
spring.mail.password=xxx
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
### 调度中心通讯TOKEN [选填]:非空时启用;
xxl.job.accessToken=
### 调度中心国际化配置 [必填]: 默认为 "zh_CN"/中文简体, 可选范围为 "zh_CN"/中文简体, "zh_TC"/中文繁体 and "en"/英文;
xxl.job.i18n=zh_CN
## 调度线程池最大线程配置【必填】
xxl.job.triggerpool.fast.max=200
xxl.job.triggerpool.slow.max=100
### 调度中心日志表数据保存天数 [必填]:过期日志自动清理;限制大于等于7时生效,否则, 如-1,关闭自动清理功能;
xxl.job.logretentiondays=30
部署项目
如果已经正确进行上述配置,可将项目编译打包部署。
调度中心访问地址:http://localhost:8080/xxl-job-admin (该地址执行器将会使用到,作为回调地址)
默认登录账号 “admin/123456”, 登录后运行界面如下图所示。
到这一步之后,调度中心的环节算是成功了,后面可以直接去看执行器部分也是可以的。
调度中心集群(可选)
调度中心支持集群部署,提升调度系统容灾和可用性。
调度中心集群部署时,几点要求和建议:
- DB配置保持一致;
- 集群机器时钟保持一致(单机集群忽视);
- 建议:推荐通过nginx为调度中心集群做负载均衡,分配域名。调度中心访问、执行器回调配置、调用API服务等操作均通过该域名进行。
其他:Docker 镜像方式搭建调度中心
- 下载镜像
// Docker地址:https://hub.docker.com/r/xuxueli/xxl-job-admin/ (建议指定版本号)docker pull xuxueli/xxl-job-admin
- 创建容器并运行
docker run -p 8080:8080 -v /tmp:/data/applogs --name xxl-job-admin -d xuxueli/xxl-job-admin:{指定版本}
/**
* 如需自定义 mysql 等配置,可通过 "-e PARAMS" 指定,参数格式 PARAMS="--key=value --key2=value2" ;
* 配置项参考文件:/xxl-job/xxl-job-admin/src/main/resources/application.properties
* 如需自定义 JVM内存参数 等配置,可通过 "-e JAVA_OPTS" 指定,参数格式 JAVA_OPTS="-Xmx512m" ;
*/
docker run -e PARAMS="--spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai" -p 8080:8080 -v /tmp:/data/applogs --name xxl-job-admin -d xuxueli/xxl-job-admin:{指定版本}
配置部署“执行器项目”
“执行器”项目:xxl-job-executor-sample-springboot (提供多种版本执行器供选择,现以 springboot 版本为例,可直接使用,也可以参考其并将现有项目改造成执行器)
作用:负责接收“调度中心”的调度并执行;可直接部署执行器,也可以将执行器集成到现有业务项目中。
执行器
这个执行器其实就是咋们自己的项目了,你的定时任务逻辑所在的Project。这里我要说明以下调度中心和执行器的关系有点类似Nacos
和微服务
之间的关系。如果大家知道Nacos注册中心的话大概可以去那么理解,各个微服务启动之后都会把自己注册到Nacos
中去,由Nacos统一来发现调度。
maven依赖
确认pom文件中引入了 “xxl-job-core” 的maven依赖;
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>2.4.0</version>
</dependency>
执行器配置
执行器配置,配置文件地址:
/xxl-job/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/resources/application.properties
执行器配置,配置内容说明:
### 调度中心部署根地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册;
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
yml如下配置
xxl:
job:
admin:
addresses: http://127.0.0.1:8080/xxl-job-admin
accessToken: default_token
executor:
address:
appname: xxl-job-executor-sample
ip:
port: 9999
logpath: /data/applogs/xxl-job/jobhandler
logretentiondays: 30
执行器组件配置
执行器组件,配置文件地址:
/xxl-job/xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/core/config/XxlJobConfig.java
参照XxlJobConfig
复制内容到自己的执行器中。
private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);
@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() {
logger.info(">>>>>>>>>>> xxl-job config init.");
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;
}
执行器集群(可选)
执行器支持集群部署,提升调度系统可用性,同时提升任务处理能力。
执行器集群部署时,几点要求和建议:
- 执行器回调地址(xxl.job.admin.addresses)需要保持一致;执行器根据该配置进行执行器自动注册等操作。
- 同一个执行器集群内AppName(xxl.job.executor.appname)需要保持一致;调度中心根据该配置动态发现不同集群的在线执行器列表。
最终启动执行器的项目看以下是否成功。
在看以下调度中心上的执行器管理中,是否成功注册。
执行效果
有人执行到这里就开始纳闷了,那我这也注册了啊,我怎么通过这些东西去执行我想要的东西呢?我们到这一步先捋一下思路,思考一下我们完成了什么。我们弄了一个调度中心,就是一个管家,然后启动了一个执行器的项目,一个马仔,并且呢这个马仔还跟管家联系上了。还没完成的是要执行任务的业务代码好像还没写,写哪里呢?又应该怎么调用执行呢?如果有些小伙伴仔细看了xxl-job的那三个子模块,很快就会发现,其实我们平时写的定时任务的业务代码它写在了执行器里,不难理解,我们通过调度中心这个管家可以随意配置一些调度信息,去管理那些马仔也就是执行器,而调度中心并不去关注具体业务逻辑是什么,它关注的是如何调度。
编写业务代码
@Component
public class TestJobTask {
/**
* 睡觉通知
*/
@XxlJob("sleepNotice")
public void sleepNotice() {
System.out.println("开始睡觉啦......");
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("醒啦........");
}
}
这里我们要注意,要使用xxl-job中的一个注解@XxlJob
,后续调度中心会根据注解里的值来找到对应的Handler,并执行里面的业务代码。
新建调度规则
启动一次
有时候我们的业务场景经常会是这样,定时任务比如每2小时一次,但是呢我们希望是部署成功后,先立马执行一次。这里我们就可以选择执行一次的按钮,先执行一次任务。
启动
这个是让任务按照设置的Cron表达式定时启动。这里是每3秒执行一次。
细说策略
路由策略
第一个:总是第一个执行。比如一个任务量很大,要三个实例同时运行,但是总是只有第一个去执行。
最后一个:总是最后一个执行。跟上面那个相反。
轮询:三个实例注册到调度中心,调度中心公平的每个都平均执行过去,所谓雨露均沾,大家都有份。
随机:这个跟轮询就相反了,大家看运气了,老天爷赏饭吃。
分片广播:这个是整个策略里重点的东西,干货的玩意。大家可以搜索度娘搜索一下相关资料,类似于可以分布式计算,比如1000W数据量的任务,利用分片广播,可以让各个注册成功的实例,去拿到对应区段的数据,互不干扰,相当于1000W的数据被切成3个通道,每个通道里只消化自己通道里的数据,这样效率就成倍提高了。其实底层原理就是执行器注册到调度中心之后,调度中心给每个执行器都分给他们2个参数,一个是机子的总数,一个是当前机子的索引数。说白了就是你家有兄弟姐妹四人,你出去逢人就说起家里人的时候,你起码得知道2个信息,一个是你爸生了四个孩子,你排第几。这2个信息你肯定是知道的,总不能说你连你爸生几个你都不知道,那还玩个毛线,如果这样的话,那么数据量有部分就无法被消费掉或者执行掉。这里面有一个很经常用到的一个概念,就是Mod,取余的方式,可以度娘搜一下。
总结
以上就是我根据xxl-job官网的中文文档配合自己的实操写出来的体会,大家可以蛮看看,如果你经常用SpringTask
的话对这个应该很快就能上手,因为我感觉它就是为了解决当初SpringTask那些轻量级定时框架留下的问题,做的一个比较全面的解决方案。
其实底层原理就是执行器注册到调度中心之后,调度中心给每个执行器都分给他们2个参数,一个是机子的总数,一个是当前机子的索引数。说白了就是你家有兄弟姐妹四人,你出去逢人就说起家里人的时候,你起码得知道2个信息,一个是你爸生了四个孩子,你排第几。这2个信息你肯定是知道的,总不能说你连你爸生几个你都不知道,那还玩个毛线,如果这样的话,那么数据量有部分就无法被消费掉或者执行掉。这里面有一个很经常用到的一个概念,就是Mod,取余的方式,可以度娘搜一下。
总结
以上就是我根据xxl-job官网的中文文档配合自己的实操写出来的体会,大家可以蛮看看,如果你经常用SpringTask
的话对这个应该很快就能上手,因为我感觉它就是为了解决当初SpringTask那些轻量级定时框架留下的问题,做的一个比较全面的解决方案。