一、xxl-job介绍
XXL-JOB是一个分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。
系统组成
- 调度模块(调度中心):
负责管理调度信息,按照调度配置发出调度请求,自身不承担业务代码。调度系统与任务解耦,提高了系统可用性和稳定性,同时调度系统性能不再受限于任务模块; 支持可视化、简单且动态的管理调度信息,包括任务新建,更新,删除,任务报警等,所有上述操作都会实时生效,同时支持监控调度结果以及执行日志。 - 执行模块(执行器):
负责接收调度请求并执行任务逻辑。任务模块专注于任务的执行等操作,开发和维护更加简单和高效; 接收“调度中心”的执行请求、终止请求和日志请求等。(执行器可以看做是业务项目)
[图片]
二、xxl-job调度中心服务部署
源码下载:
源码下载载入项目后的目录结构如下:
[图片]
- doc 目录中是官方提供的说明文档、数据库文件等
- xxl-job-admin 是调度中心服务端的源码,启动该服务可部署调度中心管理后台
- xxl-job-core 核心依赖包
- xxl-job-executor-samples 是官方为我们提供的执行器的demo
数据库初始化
数据库文件在项目中doc文件夹下 doc/db/tables_xxl_job.sql 在数据库中执行该脚本即可。
启动调度中心管理后台(xxl-job-admin)
配置文件中修改数据源配置:
xxl-job, datasource
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=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
启动项目访问:http://127.0.0.1:8080/xxl-job-admin/toLogin 用户名 / 密码:admin / 123456
[图片]
三、业务项目中集成执行器
引入maven依赖
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>2.4.0-SNAPSHOT</version>
</dependency>
添加配置类
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class 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: http://127.0.0.1:8080/xxl-job-admin ## 调度中心项目地址
accessToken: default_token ## 执行器通讯TOKEN [选填]:非空时启用
executor: ## 执行器注册 [选填]:优先使用该配置作为注册地址,为空时使用内嵌服务 ”IP:PORT“ 作为注册地址。
appname: zzh-application ##执行器名称
address: ## 执行器
ip: ## 执行器IP [选填]:默认为空表示自动获取IP
port: 9999 ## 执行器端口
logpath: d:/data/applogs/xxl-job/jobhandler ## 日志路径
logretentiondays: 30 ## 执行器日志文件保存天数
项目中创建任务代码:
import com.xxl.job.core.handler.annotation.XxlJob;
import org.springframework.stereotype.Component;
@Component
public class ZzhJob {
// 任务代码
@XxlJob("test")
public void test(){
System.out.println("test任务执行了");
}
}
@XxlJob(“test”) 该注解中的value值在调度中心创建定时任务的时候会用到
在调度中心添加执行器
@XxlJob(“test”) 该注解中的value值在调度中心创建定时任务的时候会用到同一个业务项目可以看做是一个执行器,该项目要想和调度中心建立连接,需要首先在调度中心创建该执行器,并指定执行器的注册方式 自动注册和手动录入。
[图片]
- 自动注册:执行器在启动的时候,会和调度中心建立连接,自动将该执行器的ip地址,端口等注册到调度中心
- 手动录入:需要手动在机器地址栏中输入执行器地址列表,多个执行器用逗号分隔
启动任务项目(执行器)
注意配置文件中,xxl.job.accessToken 要和调度中心中配置文件中的token一致(如启用),xxl.job.executor.appname 要和调度中心里执行器的AppName保持一致。
项目启动后,在调度中心执行器管理列表中可以看到在线的机器地址(自动注册的方式)
[图片]
此时业务项目就已经集成了执行器
四、创建定时任务及执行业务
在调度中心任务管理列表中创建任务,执行器选择刚刚创建的执行器(侳侳好 任务管理),任务描述和负责人可以自由填写,测试中调度类型填写的是cron,后面corn表达式为0/3 ? 三秒执行一次,运行默认选择BEAN,JobHandler 填写的是任务项目中@XxlJob注解中的value参数。
[图片]
创建完成后处于STOP状态,可以在操作选项中启动
[图片]
也可以选择执行一次进行测试
[图片]
至此一个简单的定时任务就配置完成了。
五、任务运行模式
BEAN模式
任务以JobHandler方式维护在执行器端,执行器中通过@XxlJob 注解指定任务的JobHandler 并且需要在调度中心创建任务时指定任务的 JobHandler。
执行器例:
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import org.springframework.stereotype.Component;
@Component
public class TestJob{
@XxlJob(value = "testJob")
public void test() {
// 获取参数
final String jobParam = XxlJobHelper.getJobParam();
System.out.println(jobParam);
XxlJobHelper.handleSuccess("执行成功");
}
}
调度中心:
[图片]
GLUE (Java)
这种方式是直接在调度中心编写代码,任务调度的时候将原代码发送到执行器进行编译和执行。
注意:
- 源码在调度中心维护
- 代码编译和执行实在执行器中执行
- 每次修改源码只会编译一次,且是在修改后第一次执行任务后编译
[图片]
java代码案例:
package com.xxl.job.service.handler;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.IJobHandler;
public class DemoGlueJobHandler extends IJobHandler {
static {
System.out.print("任务代码 初始化");
}
@Override
public void execute() throws Exception {
System.out.print("java 代码执行了")
XxlJobHelper.log("XXL-JOB, Hello World.");
}
}
GLUE (Shell)
任务以源码方式维护在调度中心;该模式的任务实际上是一段 “shell” 脚本;任务调度的时候会在执行器中执行这一段脚本。
这种任务模式可以用于定时清理和备份服务器上的执行日志等。
代码案例:
#!/bin/bash
echo 1 > /proc/sys/vm/drop_caches
exit 0
六、路由策略
当执行器集群部署时,提供丰富的路由策略,包括:
- FIRST(第一个):固定选择第一个机器;
- LAST(最后一个):固定选择最后一个机器;
- ROUND(轮询):;
- RANDOM(随机):随机选择在线的机器;
- CONSISTENT_HASH(一致性HASH):每个任务按照Hash算法固定选择某一台机器,且所有任务均匀散列在不同机器上。
- LEAST_FREQUENTLY_USED(最不经常使用):使用频率最低的机器优先被选举;
- LEAST_RECENTLY_USED(最近最久未使用):最久未使用的机器优先被选举;
- FAILOVER(故障转移):按照顺序依次进行心跳检测,第一个心跳检测成功的机器选定为目标执行器并发起调度;
- BUSYOVER(忙碌转移):按照顺序依次进行空闲检测,第一个空闲检测成功的机器选定为目标执行器并发起调度;
- SHARDING_BROADCAST(分片广播):广播触发对应集群中所有机器执行一次任务,同时系统自动传递分片参数;可根据分片参数开发分片任务;
分片广播
如果执行器集群部署的时候,而且任务执行时间较长,此时要想发挥集群中每台机器的性能,就需要使用广播分片的方式,让每台机器都处理一部分任务,从而降低处理任务的总体时间。
代码案例:
@XxlJob("sharding")
public void sharding(){
int shardIndex = XxlJobHelper.getShardIndex();
int shardTotal = XxlJobHelper.getShardTotal();
System.out.println("分片参数:当前分片序号 = "+shardIndex+", 总分片数 = "+shardTotal );
for (int i=0;i<20;i++){
if(i % shardTotal == shardIndex){
System.out.println("处理数据:"+i);
}
}
System.out.println("sharding 结束");
}
- shardIndex是当前分片序号,也是当前机器的序号,同一分片广播任务的所有机器的序号都不一样。
- shardTotal总分片数,也是总机器数,任务集群中任务服务的数量。
两台机器集群测试:
机器0:
[图片]
机器1:
[图片]
七、调度日志
[图片]
以BEAN模式为例,只要调度中心成功调度并且执行器成功执行了代码那么调度结果都是成功(常见异常为:执行器服务器连接失败、JobHandler找不到等)。至于执行结果如果代码中没有指定,那么默认执行结果就是成功。如何指定执行结果?
通过调用XxlJobHelper 类中的静态方法可以指定执行结果
XxlJobHelper.handleSuccess(String handleMsg);
执行成功,handleMsg是执行备注列展示的信息。XxlJobHelper.handleFail(String handleMsg);
执行失败。- 如果方法抛出异常则是执行失败。
例:
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import org.springframework.stereotype.Component;
@Component
public class TestJob{
@XxlJob(value = "testJob")
public void test() {
// 获取参数
final String jobParam = XxlJobHelper.getJobParam();
XxlJobHelper.handleSuccess("执行成功");
}
}