> 技术文档 > SpringCloud分布式任务调度XXL-JOB完整指南

SpringCloud分布式任务调度XXL-JOB完整指南

目录

1. XXL-JOB概述

1.1 什么是XXL-JOB

1.2 XXL-JOB的特性

1.3 XXL-JOB的优势

2. XXL-JOB架构设计

2.1 整体架构

2.2 核心组件

2.3 工作流程

3. 环境搭建与部署

3.1 环境要求

3.2 调度中心部署

3.3 数据库初始化

4. 执行器开发与配置

4.1 项目依赖配置

4.2 执行器配置

4.3 任务开发

5. 调度中心使用指南

5.1 登录与界面介绍

5.2 执行器管理

5.3 任务管理

5.4 调度日志

6. 任务类型详解

6.1 BEAN模式

6.2 GLUE模式

6.3 Shell脚本模式

7. 高级特性

7.1 分片广播

7.2 故障转移

7.3 任务依赖

7.4 动态分片

8. 监控与报警

8.1 监控指标

8.2 邮件报警

8.3 钉钉报警

9. 最佳实践

9.1 任务设计原则

9.2 性能优化

9.3 安全配置

10. 常见问题与解决方案

10.1 连接问题

10.2 任务执行问题

10.3 性能问题


1. XXL-JOB概述

1.1 什么是XXL-JOB

XXL-JOB是一个分布式任务调度平台,它的核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。

XXL-JOB解决了传统定时任务在分布式环境下面临的诸多问题:

  • 单点故障:传统的定时任务通常运行在单个服务器上,一旦服务器宕机,所有定时任务都会停止运行
  • 任务调度不灵活:缺乏统一的管理界面,任务的启停、监控都不够方便
  • 集群任务重复执行:在集群环境下,同一个定时任务可能在多个节点上同时执行
  • 任务执行状态难以监控:无法实时了解任务的执行情况和结果

XXL-JOB通过调度中心和执行器的分离架构,完美解决了这些问题,为分布式环境下的任务调度提供了一套完整的解决方案。

1.2 XXL-JOB的特性

XXL-JOB具有以下核心特性:

1. 简单易用

  • 提供Web界面,操作简单直观
  • 支持多种任务模式,满足不同场景需求
  • 丰富的任务调度策略和执行策略

2. 动态管理

  • 支持动态修改任务状态、启动/停止任务
  • 支持动态修改任务执行参数
  • 支持任务优先级设置

3. 调度中心HA(高可用)

  • 调度中心支持集群部署,保证调度系统的高可用性
  • 调度中心通过数据库锁保证集群分布式调度的一致性

4. 执行器HA(高可用)

  • 执行器支持集群部署,支持动态扩容
  • 任务分布式执行,任务\"故障转移\"

5. 注册中心

  • 执行器会周期性自动注册任务,调度中心将会自动发现注册的任务并触发执行
  • 执行器自动注册撤销,调度中心将会自动移除

6. 弹性扩容缩容

  • 一旦有新执行器机器上线或者下线,下次调度时将会重新分配任务

7. 触发策略

  • 提供丰富的任务触发策略:包括:Cron触发、固定间隔触发、固定延时触发、API(事件)触发、人工触发、父子任务触发

8. 调度过期策略

  • 调度中心错过调度时间的补偿处理策略,包括:忽略、立即补偿触发一次等

9. 阻塞处理策略

  • 调度过于密集执行器来不及处理时的处理策略,包括:单机串行(默认)、丢弃后续调度、覆盖之前调度

10. 任务超时控制

  • 支持自定义任务超时时间,任务运行超时将会主动中断任务

11. 任务失败重试

  • 支持自定义任务失败重试次数,当任务失败时将会按照预设的失败重试次数主动进行重试

12. 任务失败告警

  • 默认提供邮件方式失败告警,同时预留扩展接口,可方便的扩展短信、钉钉等告警方式

13. 路由策略

  • 执行器集群部署时提供丰富的路由策略,包括:第一个、最后一个、轮询、随机、一致性HASH、最不经常使用、最近最久未使用、故障转移、忙碌转移等

14. 分片广播任务

  • 执行器集群部署时,任务路由策略选择\"分片广播\"情况下,一次任务调度将会广播触发集群中所有执行器执行一次任务,可根据分片参数开发分片任务

15. 动态分片

  • 分片广播任务以执行器为维度进行分片,支持动态扩容执行器集群从而动态增加分片数量,协同进行业务处理;在进行大数据量业务操作时可显著提升任务处理能力和速度

16. 故障转移

  • 任务路由策略选择\"故障转移\"情况下,如果执行器集群中某一台机器故障,将会自动Failover切换到一台正常的执行器发送调度请求

17. 任务进度监控

  • 支持实时监控任务进度

1.3 XXL-JOB的优势

相比其他任务调度框架,XXL-JOB具有以下优势:

与Quartz对比:

  • XXL-JOB提供了Web管理界面,而Quartz需要自己开发
  • XXL-JOB支持分布式部署和故障转移,Quartz在集群环境下存在问题
  • XXL-JOB提供了丰富的路由策略,Quartz相对简单

与Elastic-Job对比:

  • XXL-JOB部署更简单,不依赖Zookeeper
  • XXL-JOB的Web界面更加友好
  • XXL-JOB的学习成本更低

与Spring Task对比:

  • XXL-JOB支持分布式调度,Spring Task只支持单机
  • XXL-JOB提供了完整的任务管理功能
  • XXL-JOB支持多种执行策略

2. XXL-JOB架构设计

2.1 整体架构

XXL-JOB采用\"调度中心\"与\"执行器\"分离的架构设计:

调度中心 (xxl-job-admin) ↓ (HTTP调用)执行器 (xxl-job-executor) ↓ (执行)业务任务 (JobHandler)

架构特点:

  • 调度中心:负责管理调度信息,按照调度配置发出调度请求,自身不承担业务代码
  • 执行器:负责接收调度请求并执行对应的JobHandler中业务代码
  • 任务:负责执行具体的业务逻辑

这种设计的好处:

  1. 职责清晰:调度和执行分离,各司其职
  2. 易于维护:调度中心专注于调度逻辑,执行器专注于任务执行
  3. 高可用:调度中心和执行器都可以集群部署
  4. 易扩展:新增执行器节点即可实现水平扩展

2.2 核心组件

1. 调度中心(xxl-job-admin)

调度中心是XXL-JOB的核心组件,主要功能包括:

  • 任务管理:提供Web界面进行任务的增删改查
  • 调度器:根据配置的调度策略触发任务执行
  • 执行器管理:管理执行器的注册、注销和心跳检测
  • 调度日志:记录任务执行的详细日志
  • 报警通知:任务执行失败时发送报警通知
  • 用户管理:支持多用户和权限管理

2. 执行器(xxl-job-executor)

执行器是任务的实际执行者,主要功能包括:

  • 任务执行:接收调度中心的调度请求,执行具体的业务逻辑
  • 自动注册:启动时自动向调度中心注册
  • 心跳检测:定期向调度中心发送心跳,证明自己存活
  • 任务回调:将任务执行结果回调给调度中心
  • 日志收集:收集任务执行过程中的日志信息

3. 任务处理器(JobHandler)

任务处理器是具体的业务逻辑实现,主要特点:

  • 业务无关:XXL-JOB只负责调度,不关心具体业务
  • 多种模式:支持Bean模式、GLUE模式、Shell脚本模式等
  • 参数传递:支持从调度中心传递参数到任务处理器
  • 结果返回:支持将执行结果返回给调度中心

2.3 工作流程

XXL-JOB的完整工作流程如下:

1. 初始化阶段

1. 调度中心启动,初始化调度器2. 执行器启动,向调度中心注册3. 调度中心接收执行器注册信息4. 执行器开始定期发送心跳

2. 任务调度阶段

1. 调度中心扫描待执行任务2. 根据调度策略计算下次执行时间3. 根据路由策略选择执行器4. 向执行器发送调度请求5. 执行器接收请求并执行任务6. 执行器将结果回调给调度中心7. 调度中心记录执行日志

3. 异常处理阶段

1. 执行器心跳超时,标记为不可用2. 任务执行失败,根据重试配置进行重试3. 重试次数用完,发送失败告警4. 根据路由策略进行故障转移

3. 环境搭建与部署

3.1 环境要求

在开始部署XXL-JOB之前,需要准备以下环境:

基础环境:

  • JDK:1.8及以上版本
  • Maven:3.3及以上版本
  • MySQL:5.6及以上版本(推荐5.7+)
  • Tomcat:8.5及以上版本(如果需要独立部署)

推荐配置:

  • 操作系统:Linux(CentOS 7+、Ubuntu 16.04+)
  • 内存:调度中心至少2GB,执行器根据业务需求
  • 存储:至少10GB可用空间
  • 网络:调度中心和执行器之间网络通畅

3.2 调度中心部署

步骤1:下载源码

# 从GitHub下载源码git clone https://github.com/xuxueli/xxl-job.gitcd xxl-job# 或者下载Release版本wget https://github.com/xuxueli/xxl-job/archive/2.4.0.tar.gz

步骤2:修改配置文件

编辑 xxl-job-admin/src/main/resources/application.properties

# 数据库配置spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghaispring.datasource.username=rootspring.datasource.password=root_pwdspring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver# MyBatis配置mybatis.mapper-locations=classpath:/mybatis-mapper/*Mapper.xml# 调度中心部署根地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin# 调度中心通讯TOKEN [选填]:非空时启用xxl.job.accessToken=default_token# 调度中心国际化配置 [必填]:默认为 \"zh_CN\"/中文简体, 可选范围为 \"zh_CN\"/中文简体, \"zh_TC\"/中文繁体 and \"en\"/英文;xxl.job.i18n=zh_CN# 调度线程池最大线程配置【必填】xxl.job.triggerpool.fast.max=200xxl.job.triggerpool.slow.max=100# 调度中心日志表数据保存天数 [必填]:过期自动清理; 限制大于等于7时生效,否则, 如-1,关闭自动清理功能;xxl.job.logretentiondays=30# 邮件配置spring.mail.host=smtp.qq.comspring.mail.port=25spring.mail.username=xxx@qq.comspring.mail.password=xxxspring.mail.properties.mail.smtp.auth=truespring.mail.properties.mail.smtp.starttls.enable=truespring.mail.properties.mail.smtp.starttls.required=truespring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory

步骤3:编译和打包

# 进入调度中心目录cd xxl-job-admin# 使用Maven编译打包mvn clean package -Dmaven.test.skip=true

步骤4:启动调度中心

# 方式1:直接运行jar包java -jar target/xxl-job-admin-2.4.0.jar# 方式2:后台运行nohup java -jar target/xxl-job-admin-2.4.0.jar > xxl-job-admin.log 2>&1 &# 方式3:指定配置文件java -jar target/xxl-job-admin-2.4.0.jar --spring.config.location=classpath:/application.properties

步骤5:访问调度中心

启动成功后,访问 http://localhost:8080/xxl-job-admin

  • 默认用户名:admin
  • 默认密码:123456

3.3 数据库初始化

XXL-JOB需要使用MySQL数据库存储调度信息,需要先创建数据库和表结构。

步骤1:创建数据库

CREATE DATABASE xxl_job DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

步骤2:执行建表脚本

执行源码目录下的SQL脚本:/doc/db/tables_xxl_job.sql

-- 创建调度锁表CREATE TABLE xxl_job_lock ( lock_name varchar(50) NOT NULL COMMENT \'锁名称\', PRIMARY KEY (lock_name)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT=\'任务调度锁表\';-- 创建任务信息表CREATE TABLE xxl_job_info ( id int(11) NOT NULL AUTO_INCREMENT, job_group int(11) NOT NULL COMMENT \'执行器主键ID\', job_desc varchar(255) NOT NULL, add_time datetime DEFAULT NULL, update_time datetime DEFAULT NULL, author varchar(64) DEFAULT NULL COMMENT \'作者\', alarm_email varchar(255) DEFAULT NULL COMMENT \'报警邮件\', schedule_type varchar(50) NOT NULL DEFAULT \'NONE\' COMMENT \'调度类型\', schedule_conf varchar(128) DEFAULT NULL COMMENT \'调度配置\', misfire_strategy varchar(50) NOT NULL DEFAULT \'DO_NOTHING\' COMMENT \'调度过期策略\', executor_route_strategy varchar(50) DEFAULT NULL COMMENT \'执行器路由策略\', executor_handler varchar(255) DEFAULT NULL COMMENT \'执行器任务handler\', executor_param varchar(512) DEFAULT NULL COMMENT \'执行器任务参数\', executor_block_strategy varchar(50) DEFAULT NULL COMMENT \'阻塞处理策略\', executor_timeout int(11) NOT NULL DEFAULT \'0\' COMMENT \'任务执行超时时间,单位秒\', executor_fail_retry_count int(11) NOT NULL DEFAULT \'0\' COMMENT \'失败重试次数\', glue_type varchar(50) NOT NULL COMMENT \'GLUE类型\', glue_source mediumtext COMMENT \'GLUE源代码\', glue_remark varchar(128) DEFAULT NULL COMMENT \'GLUE备注\', glue_updatetime datetime DEFAULT NULL COMMENT \'GLUE更新时间\', child_jobid varchar(255) DEFAULT NULL COMMENT \'子任务ID,多个逗号分隔\', trigger_status tinyint(4) NOT NULL DEFAULT \'0\' COMMENT \'调度状态:0-停止,1-运行\', trigger_last_time bigint(13) NOT NULL DEFAULT \'0\' COMMENT \'上次调度时间\', trigger_next_time bigint(13) NOT NULL DEFAULT \'0\' COMMENT \'下次调度时间\', PRIMARY KEY (id)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;-- 其他表的创建语句...

关键表说明:

  • xxl_job_info:存储任务信息
  • xxl_job_log:存储任务执行日志
  • xxl_job_group:存储执行器信息
  • xxl_job_user:存储用户信息
  • xxl_job_lock:分布式锁表

4. 执行器开发与配置

4.1 项目依赖配置

在Spring Boot项目中集成XXL-JOB执行器,首先需要添加相关依赖。

步骤1:添加Maven依赖

pom.xml 文件中添加以下依赖:

   org.springframework.boot spring-boot-starter-web    com.xuxueli xxl-job-core 2.4.0    org.springframework.boot spring-boot-starter-jdbc   mysql mysql-connector-java 

步骤2:版本兼容性说明

不同版本的XXL-JOB对Spring Boot版本有不同要求:

  • XXL-JOB 2.4.x:支持Spring Boot 2.0+
  • XXL-JOB 2.3.x:支持Spring Boot 1.5+ 和 2.0+
  • XXL-JOB 2.2.x:支持Spring Boot 1.5+

4.2 执行器配置

步骤1:配置文件设置

application.ymlapplication.properties 中添加XXL-JOB配置:

# application.yml 配置方式xxl: job: admin: addresses: http://127.0.0.1:8080/xxl-job-admin # 调度中心地址 executor: appname: xxl-job-executor-sample  # 执行器名称 address:  # 执行器地址,为空则自动获取 ip: # 执行器IP,为空则自动获取 port: 9999 # 执行器端口 logpath: /data/applogs/xxl-job/jobhandler # 执行器日志路径 logretentiondays: 30 # 执行器日志保留天数 accessToken: default_token # 通讯TOKEN
# application.properties 配置方式xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-adminxxl.job.executor.appname=xxl-job-executor-samplexxl.job.executor.address=xxl.job.executor.ip=xxl.job.executor.port=9999xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandlerxxl.job.executor.logretentiondays=30xxl.job.accessToken=default_token

配置参数详解:

  • addresses:调度中心地址,多个地址用逗号分隔
  • appname:执行器名称,执行器心跳注册分组依据,必须唯一
  • address:执行器地址,执行器\"自动注册\"时对外地址,为空则使用内嵌服务的地址
  • ip:执行器IP,默认为空表示自动获取IP
  • port:执行器端口,小于等于0则自动获取
  • logpath:执行器运行日志文件存储磁盘路径
  • logretentiondays:执行器日志保留天数,值为-1时关闭自动清理功能
  • accessToken:通讯TOKEN,调度中心和执行器保持一致

步骤2:创建配置类

@Configurationpublic 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 XxlJobExecutor xxlJobExecutor() { XxlJobExecutor xxlJobExecutor = new XxlJobExecutor(); xxlJobExecutor.setAdminAddresses(adminAddresses); xxlJobExecutor.setAppname(appname); xxlJobExecutor.setAddress(address); xxlJobExecutor.setIp(ip); xxlJobExecutor.setPort(port); xxlJobExecutor.setAccessToken(accessToken); xxlJobExecutor.setLogPath(logPath); xxlJobExecutor.setLogRetentionDays(logRetentionDays); return xxlJobExecutor; }}

4.3 任务开发

XXL-JOB支持多种任务开发模式,其中BEAN模式是最常用的方式。

步骤1:创建任务处理器

@Componentpublic class SampleJobHandler { /** * 简单任务示例(Bean模式) */ @XxlJob(\"demoJobHandler\") public void demoJobHandler() throws Exception { XxlJobHelper.log(\"XXL-JOB, Hello World.\"); // 模拟业务处理 for (int i = 0; i < 5; i++) { XxlJobHelper.log(\"beat at:\" + i); TimeUnit.SECONDS.sleep(2); } } /** * 带参数的任务示例 */ @XxlJob(\"paramJobHandler\") public void paramJobHandler() throws Exception { // 获取调度参数 String param = XxlJobHelper.getJobParam(); XxlJobHelper.log(\"参数值:\" + param); // 处理业务逻辑 if (StringUtils.hasText(param)) { String[] params = param.split(\",\"); for (String p : params) { XxlJobHelper.log(\"处理参数:\" + p); // 具体业务处理 } } } /** * 可中断的任务示例 */ @XxlJob(\"interruptibleJobHandler\") public void interruptibleJobHandler() throws Exception { for (int i = 0; i < 100; i++) { // 检查是否收到中断信号 if (XxlJobHelper.isStopped()) { XxlJobHelper.log(\"任务被中断,停止执行\"); return; } XxlJobHelper.log(\"执行步骤:\" + i); TimeUnit.SECONDS.sleep(1); } } /** * 数据处理任务示例 */ @XxlJob(\"dataProcessJobHandler\") public void dataProcessJobHandler() throws Exception { try { // 模拟数据处理 List dataList = Arrays.asList(\"data1\", \"data2\", \"data3\"); for (String data : dataList) { // 检查是否被中断 if (XxlJobHelper.isStopped()) {  break; } // 处理数据 processData(data); XxlJobHelper.log(\"处理完成:\" + data); } // 设置任务执行结果 XxlJobHelper.handleSuccess(\"数据处理任务执行成功\");  } catch (Exception e) { XxlJobHelper.log(\"任务执行异常:\" + e.getMessage()); XxlJobHelper.handleFail(\"任务执行失败:\" + e.getMessage()); } } private void processData(String data) throws InterruptedException { // 模拟数据处理耗时 TimeUnit.SECONDS.sleep(2); } /** * 分片任务示例 */ @XxlJob(\"shardingJobHandler\") public void shardingJobHandler() throws Exception { // 获取分片参数 int shardIndex = XxlJobHelper.getShardIndex(); int shardTotal = XxlJobHelper.getShardTotal(); XxlJobHelper.log(\"分片参数:当前分片序号 = {}, 总分片数 = {}\", shardIndex, shardTotal); // 根据分片参数处理数据 List dataList = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); for (int i = 0; i < dataList.size(); i++) { // 根据分片规则分配数据 if (i % shardTotal == shardIndex) { Integer data = dataList.get(i); XxlJobHelper.log(\"分片{}处理数据:{}\", shardIndex, data); // 处理业务逻辑 TimeUnit.SECONDS.sleep(1); } } }}

步骤2:任务处理器注解说明

@XxlJob 注解是XXL-JOB的核心注解,用于标识一个方法为任务处理器:

@XxlJob(value = \"jobHandlerName\", init = \"init\", destroy = \"destroy\")
  • value:任务处理器名称,必须唯一,对应调度中心配置的JobHandler属性