前言
XXL-JOB是一个轻量级分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。
官方地址中文版:http://www.xuxueli.com/xxl-job
一、Quartz的对比
Quartz作为开源作业调度中的佼佼者,是作业调度的首选。集群环境中Quartz采用API的方式对任务进行管理,Quartz存在以下问题:
- 调用API的的方式操作任务,不人性化
- 需要持久化业务QuartzJobBean到底层数据表中,系统侵入性相当严重
- 调度逻辑和QuartzJobBean耦合在同一个项目中,调度系统的性能将大大受限于业务
- quartz底层以“抢占式”获取DB锁并由抢占成功节点负责运行任务,节点负载悬虚大,而XXL-JOB通过执行器实现“协同分配式”运行任务,负载各个节点
二、XXL-JOB特性
XXL-JOB特性太过于多,这里就挑几个有点比较大的来说说
- 简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手
- 调度中心HA(中心式):调度采用中心式设计,“调度中心”基于集群Quartz实现并支持集群部署,可保证调度中心HA
- 执行器HA(分布式):任务分布式执行,任务"执行器"支持集群部署
- 任务失败重试:支持自定义任务失败重试次数
- 邮件报警:任务失败时支持邮件报警,支持配置多邮件地址群发报警邮件
- 自定义任务参数:支持在线配置调度任务入参,即时生效
- 跨平台:原生提供通用HTTP任务Handler(Bean任务,"HttpJobHandler"),业务方只需要提供HTTP链接即可,不限制语言、平台
- 全异步:任务调度流程全异步化设计实现,如异步调度、异步运行、异步回调等,有效对密集调度进行流量削峰,理论上支持任意时长任务的运行
- 容器化:提供官方docker镜像,并实时更新推送dockerhub,进一步实现产品开箱即用
- 线程池隔离:调度线程池进行隔离拆分,避免耗尽调度线程,提高系统稳定性
- 一致性:“调度中心”通过DB锁保证集群分布式调度的一致性, 一次任务调度只会触发一次执行
使用xxl-job需要两大步骤,分为客户端(源码下载启动后台),服务端
三、快速入门(客户端)
3.1、官网下载源码
- xxl-job-admin:调度中心
- xxl-job-core:公共依赖
- xxl-job-executor-samples:执行器Sample示例
3.2、初始化"调度数据库"
SQL脚本位置:/xxl-job/doc/db/tables_xxl_job.sql
注意⚠️:调度中心支持集群部署,集群情况下各节点务必连接同一个mysql实例;
如果mysql做主从,调度中心集群节点务必强制走主库
3.3、修改xxl-job-admin配置
我这里就把需要改的几个地方列出来了
### 端口,随自己修改
server.port=8096
server.servlet.context-path=/xxl-job-admin
### 数据库
spring.datasource.url=jdbc:mysql://49.233.170.48:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=Qw941104/
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
### 邮箱(qq邮箱密码你要去查看授权码)
spring.mail.host=smtp.qq.com
spring.mail.port=25
spring.mail.username=1050674486@qq.com
spring.mail.from=1050674486@qq.com
spring.mail.password=
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
# 管理界面的登录用户名密码
xxl.job.login.username=admin
xxl.job.login.password=123456
3.4、启动部署
http://127.0.0.1:8096/xxl-job-admin
界面
至此“调度中心”项目已经部署成功。
四、springboot整合执行器项目
4.1、examples范例
你说下载的项目中这个就是范例,有不同版本,我下面自己搭建
4.2、依赖引入
dependencies {
compile("org.springframework.boot:spring-boot-starter-web:$springbootWebVersion")
compile("com.xuxueli:xxl-job-core:2.2.0")
}
4.2、配置
其中注意xxl.job.admin.addresses
# web port
server.port=8095
# no web
#spring.main.web-environment=false
# log config
logging.config=classpath:logback.xml
### xxl-job admin address list, such as "http://address" or "http://address01,http://address02"
xxl.job.admin.addresses=http://127.0.0.1:8096/xxl-job-admin
### xxl-job, access token
xxl.job.accessToken=
### xxl-job executor appname
xxl.job.executor.appname=xxl-job-executor-sample
### xxl-job executor registry-address: default use address to registry , otherwise use ip:port if address is null
xxl.job.executor.address=
### xxl-job executor server-info
xxl.job.executor.ip=
xxl.job.executor.port=9999
### xxl-job executor log-path
xxl.job.executor.logpath=data/applogs/xxl-job/jobhandler
### xxl-job executor log-retention-days
xxl.job.executor.logretentiondays=30
4.3、配置
@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;
}
/**
* 针对多网卡、容器内部署等情况,可借助 "spring-cloud-commons" 提供的 "InetUtils" 组件灵活定制注册IP;
*
* 1、引入依赖:
* <dependency>
* <groupId>org.springframework.cloud</groupId>
* <artifactId>spring-cloud-commons</artifactId>
* <version>${version}</version>
* </dependency>
*
* 2、配置文件,或者容器启动变量
* spring.cloud.inetutils.preferred-networks: 'xxx.xxx.xxx.'
*
* 3、获取IP
* String ip_ = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress();
*/
}
到这里我们就搭建好了,接下来开发自己的任务
五、自定义任务
5.1、自定义任务
@Component
public class SampleXxlJob {
@Autowired
DemoJobService demoJobService;
/**
* 1、简单任务示例(Bean模式)
*/
@XxlJob("demoJobHandler")
public ReturnT<String> execute(String param) {
XxlJobLogger.log("hello world.");
demoJobService.demoTest(param);
return ReturnT.SUCCESS;
}
}
4.5、逻辑处理(不重要)
@Service
@Slf4j
public class DemoJobService {
public void demoTest(String s1) {
log.info("====逻辑处理中==========参数:{}", s1);
}
}
5.2、客户端新建执行器
5.3、客户端新建任务
5.4、启动或者执行一次
5.5、控制台打印日志
六、配置属性详细说明:
-
执行器:任务的绑定的执行器,任务触发调度时将会自动发现注册成功的执行器, 实现任务自动发现功能; 另一方面也可以方便的进行任务分组。每个任务必须绑定一个执行器, 可在 "执行器管理" 进行设置;
-
任务描述:任务的描述信息,便于任务管理;
-
路由策略:当执行器集群部署时,提供丰富的路由策略,包括;
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所对应的任务的一次主动调度。
-
任务超时时间:支持自定义任务超时时间,任务运行超时将会主动中断任务;
-
失败重试次数;支持自定义任务失败重试次数,当任务失败时将会按照预设的失败重试次数主动进行重试;
-
报警邮件:任务调度失败时邮件通知的邮箱地址,支持配置多邮箱地址,配置多个邮箱地址时用逗号分隔;
-
负责人:任务的负责人;
-
执行参数:任务执行所需的参数;
七、注意事项
7.1、报错:The correct method format like " public ReturnT execute(String param) "
你开发的自定义任务bean返回错误或者参数
7.2、报错500
请检查你的依赖是否冲突