xxl-job入门教程 - 分布式任务调度平台完整指南
xxl-job入门教程 - 分布式任务调度平台完整指南
目录
1. xxl-job简介
xxl-job是一个轻量级分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。
核心特性:
- ✅ 简单易用:支持通过Web界面管理任务,操作简单
- ✅ 动态配置:支持动态修改任务配置、暂停/恢复任务
- ✅ 执行器Failover:支持执行器Failover,提高系统可用性
- ✅ 任务分片:支持任务分片执行,提高任务处理能力
- ✅ 失败重试:支持失败重试机制,提高任务执行成功率
- ✅ 任务依赖:支持任务依赖,实现复杂任务流程
- ✅ 任务监控:提供完善的任务监控和日志查看功能
- ✅ 多语言支持:支持Java、Python、PHP、Node.js等多种语言
┌─────────────────┐
│ 调度中心 │
│ (调度中心集群) │
└────────┬─────────┘
│
│ HTTP/调度
│
┌────┴────┐
│ │
┌───▼───┐ ┌──▼───┐
│执行器1│ │执行器2│
│(集群) │ │(集群) │
└───────┘ └──────┘核心组件:
- 调度中心:负责任务的调度和管理
- 执行器:负责任务的实际执行
- 任务:需要执行的具体业务逻辑
| 特性 | xxl-job | Quartz | Elastic-Job |
|---|---|---|---|
| 学习成本 | 低 | 中 | 高 |
| 功能丰富度 | 高 | 中 | 高 |
| 分布式支持 | 是 | 否 | 是 |
| Web管理界面 | 是 | 否 | 是 |
| 动态配置 | 是 | 否 | 是 |
| 社区活跃度 | 高 | 中 | 低 |
- 定时任务调度
- 数据同步
- 报表生成
- 数据清理
- 消息推送
- 批量处理
- 分布式任务处理
2. 环境准备
- JDK:1.8+
- Maven:3.6+
- MySQL:5.7+ 或 8.0+
- IDE:IntelliJ IDEA、Eclipse等
方式一:GitHub下载
git clone https://github.com/xuxueli/xxl-job.git
cd xxl-job方式二:直接下载
访问GitHub Releases页面下载最新版本:
https://github.com/xuxueli/xxl-job/releases
创建数据库
CREATE DATABASE IF NOT EXISTS `xxl_job` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE `xxl_job`;执行SQL脚本
在xxl-job/doc/db/tables_xxl_job.sql文件中找到SQL脚本,执行创建表:
主要表结构:
xxl_job_info:任务信息表xxl_job_log:任务执行日志表xxl_job_registry:执行器注册表xxl_job_group:执行器组表xxl_job_user:用户表
修改配置文件
编辑xxl-job/xxl-job-admin/src/main/resources/application.properties:
### 调度中心配置
server.port=8080
server.servlet.context-path=/xxl-job-admin
### 数据库配置
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
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
### 登录配置
xxl.job.login.username=admin
xxl.job.login.password=123456
### 日志配置
xxl.job.logretentiondays=30启动调度中心
方式一:使用IDE启动
- 导入项目到IDE
- 找到
XxlJobAdminApplication主类 - 运行main方法
方式二:使用Maven启动
cd xxl-job/xxl-job-admin
mvn spring-boot:run方式三:打包后启动
cd xxl-job/xxl-job-admin
mvn clean package
java -jar target/xxl-job-admin-2.4.0.jar访问调度中心
启动成功后,访问:http://localhost:8080/xxl-job-admin
默认账号密码:
- 用户名:
admin - 密码:
123456
3. 快速开始
mvn archetype:generate -DgroupId=com.example -DartifactId=xxl-job-executor -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false在pom.xml中添加xxl-job依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>xxl-job-executor</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<xxl-job.version>2.4.0</xxl-job.version>
<spring-boot.version>2.7.0</spring-boot.version>
</properties>
<dependencies>
<!-- xxl-job-core -->
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>${xxl-job.version}</version>
</dependency>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- Spring Boot Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring-boot.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>创建application.properties配置文件:
### 调度中心部署地址
xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin
### 执行器AppName
xxl.job.executor.appname=xxl-job-executor-sample
### 执行器注册地址
xxl.job.executor.address=
### 执行器IP
xxl.job.executor.ip=
### 执行器端口号
xxl.job.executor.port=9999
### 执行器日志文件存储路径
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
### 执行器日志文件保存天数
xxl.job.executor.logretentiondays=30package com.example.config;
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.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.setLogPath(logPath);
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
return xxlJobSpringExecutor;
}
}package com.example.job;
import com.xxl.job.core.handler.annotation.XxlJob;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class SampleXxlJob {
private static Logger logger = LoggerFactory.getLogger(SampleXxlJob.class);
/**
* 示例任务
*/
@XxlJob("demoJobHandler")
public void demoJobHandler() throws Exception {
logger.info("XXL-JOB, Hello World.");
// 模拟业务处理
for (int i = 0; i < 5; i++) {
logger.info("处理任务: " + i);
Thread.sleep(1000);
}
logger.info("任务执行完成");
}
}创建Spring Boot主类:
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class XxlJobExecutorApplication {
public static void main(String[] args) {
SpringApplication.run(XxlJobExecutorApplication.class, args);
}
}启动执行器应用。
添加执行器:
- 进入"执行器管理"
- 点击"新增"
- 填写执行器信息:
- AppName:
xxl-job-executor-sample - 名称:
示例执行器 - 注册方式:
自动注册
- AppName:
- 保存
添加任务:
- 进入"任务管理"
- 点击"新增"
- 填写任务信息:
- 执行器: 选择刚创建的执行器
- 任务描述:
示例任务 - 运行模式:
BEAN - JobHandler:
demoJobHandler - Cron:
0/30 * * * * ?(每30秒执行一次) - 运行模式:
BEAN
- 保存
启动任务:
- 在任务列表中,点击"启动"按钮
- 任务将按照Cron表达式自动执行
查看日志:
- 点击"执行日志"查看任务执行情况
- 可以查看执行时间、执行状态、日志内容等
4. 核心概念
调度中心是xxl-job的核心组件,负责任务的调度和管理。
主要功能:
- 任务管理:任务的增删改查
- 任务调度:按照Cron表达式调度任务
- 执行器管理:管理执行器注册信息
- 日志查看:查看任务执行日志
- 用户管理:管理系统用户
执行器是实际执行任务的组件。
主要功能:
- 注册到调度中心
- 接收调度中心的调度请求
- 执行具体的任务逻辑
- 上报执行结果
任务是具体的业务逻辑,需要在执行器中实现。
任务类型:
- BEAN模式:通过JobHandler名称调用Spring Bean
- GLUE模式:通过Groovy脚本动态执行
- SHELL模式:执行Shell脚本
- PYTHON模式:执行Python脚本
JobHandler是任务的唯一标识,在BEAN模式下对应方法上的@XxlJob注解值。
Cron表达式用于定义任务的执行时间。
常用Cron表达式:
// 每5秒执行一次
"0/5 * * * * ?"
// 每分钟执行一次
"0 * * * * ?"
// 每小时执行一次
"0 0 * * * ?"
// 每天凌晨2点执行
"0 0 2 * * ?"
// 每周一凌晨2点执行
"0 0 2 ? * MON"
// 每月1号凌晨2点执行
"0 0 2 1 * ?"
// 每天上午10点15分执行
"0 15 10 * * ?"Cron表达式格式:
秒 分 时 日 月 周 [年]5. 执行器开发
简单任务
@Component
public class SimpleJob {
private static Logger logger = LoggerFactory.getLogger(SimpleJob.class);
@XxlJob("simpleJobHandler")
public void simpleJobHandler() {
logger.info("简单任务执行");
// 业务逻辑
}
}带参数的任务
@Component
public class ParamJob {
private static Logger logger = LoggerFactory.getLogger(ParamJob.class);
@XxlJob("paramJobHandler")
public void paramJobHandler(String param) {
logger.info("接收参数: {}", param);
// 使用参数处理业务逻辑
}
}分片任务
@Component
public class ShardingJob {
private static Logger logger = LoggerFactory.getLogger(ShardingJob.class);
@XxlJob("shardingJobHandler")
public void shardingJobHandler() {
// 获取分片参数
int shardIndex = XxlJobHelper.getShardIndex();
int shardTotal = XxlJobHelper.getShardTotal();
logger.info("分片参数:当前分片序号 = {}, 总分片数 = {}", shardIndex, shardTotal);
// 根据分片参数处理数据
List<String> dataList = getDataList();
int dataSize = dataList.size();
int perShard = dataSize / shardTotal;
int start = shardIndex * perShard;
int end = (shardIndex == shardTotal - 1) ? dataSize : (shardIndex + 1) * perShard;
for (int i = start; i < end; i++) {
processData(dataList.get(i));
}
}
private List<String> getDataList() {
// 获取待处理数据
return Arrays.asList("data1", "data2", "data3", "data4", "data5");
}
private void processData(String data) {
logger.info("处理数据: {}", data);
}
}@Component
public class ReturnValueJob {
@XxlJob("returnValueJobHandler")
public void returnValueJobHandler() {
// 设置任务执行结果
XxlJobHelper.handleSuccess("任务执行成功");
// 或者设置失败
// XxlJobHelper.handleFail("任务执行失败");
}
}@Component
public class LogJob {
@XxlJob("logJobHandler")
public void logJobHandler() {
// 使用XxlJobHelper记录日志(会记录到调度中心)
XxlJobHelper.log("开始执行任务");
// 使用普通logger记录日志(记录到本地文件)
logger.info("本地日志");
XxlJobHelper.log("任务执行完成");
}
}@Component
public class TimeoutJob {
@XxlJob("timeoutJobHandler")
public void timeoutJobHandler() {
// 设置任务超时时间(秒)
XxlJobHelper.handleTimeout(60);
// 执行可能耗时的操作
doLongRunningTask();
}
}6. 任务配置与管理
基本信息:
- 执行器:选择任务所属的执行器
- 任务描述:任务的描述信息
- 负责人:任务负责人
- 报警邮件:任务失败时发送告警邮件
调度配置:
- 调度类型:
- CRON:Cron表达式调度
- FIXED_RATE:固定频率调度
- Cron:Cron表达式
- 运行模式:
- BEAN:Bean模式
- GLUE:GLUE模式
- JobHandler:JobHandler名称(BEAN模式)
执行配置:
- 路由策略:任务的路由策略
- 子任务ID:子任务ID,多个用逗号分隔
- 任务超时时间:任务执行超时时间(秒)
- 失败重试次数:任务失败后的重试次数
高级配置:
- 阻塞处理策略:任务阻塞时的处理策略
- 任务参数:任务执行参数
任务状态:
- 停止:任务已停止,不会执行
- 运行中:任务正在运行
- 暂停:任务已暂停
操作:
- 启动:启动任务
- 停止:停止任务
- 执行一次:立即执行一次任务
- 编辑:编辑任务配置
- 删除:删除任务
执行日志:
- 查看任务执行历史
- 查看执行时间、执行状态
- 查看执行日志内容
- 支持日志搜索和过滤
调度报表:
- 查看任务调度统计
- 查看任务执行成功率
- 查看任务执行时长统计
7. 任务类型详解
BEAN模式是最常用的模式,通过JobHandler名称调用Spring Bean中的方法。
优点:
- 性能好
- 类型安全
- 易于调试
示例:
@Component
public class BeanModeJob {
@XxlJob("beanModeJobHandler")
public void execute() {
// 业务逻辑
}
}GLUE模式支持Groovy脚本,可以动态修改任务逻辑。
使用场景:
- 需要频繁修改任务逻辑
- 任务逻辑简单
- 不需要编译部署
示例:
在调度中心配置任务时,选择运行模式为GLUE,然后在GLUE代码编辑器中编写Groovy代码:
package com.xxl.job.core.glue.impl;
import com.xxl.job.core.glue.GlueExecutor;
import com.xxl.job.core.log.XxlJobLogger;
public class GlueJobHandler implements GlueExecutor {
@Override
public void execute(String param) throws Exception {
XxlJobLogger.log("GLUE模式任务执行");
XxlJobLogger.log("参数: " + param);
// 业务逻辑
}
}SHELL模式用于执行Shell脚本。
示例:
#!/bin/bash
echo "执行Shell脚本"
# 业务逻辑PYTHON模式用于执行Python脚本。
示例:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
print("执行Python脚本")
# 业务逻辑8. 路由策略
1. FIRST(第一个)
- 选择第一个执行器
- 适用于单机部署
2. LAST(最后一个)
- 选择最后一个执行器
- 适用于单机部署
3. ROUND(轮询)
- 轮询选择执行器
- 适用于负载均衡
4. RANDOM(随机)
- 随机选择执行器
- 适用于负载均衡
5. CONSISTENT_HASH(一致性HASH)
- 根据任务参数进行一致性HASH
- 相同参数的任务会路由到同一个执行器
6. LEAST_FREQUENTLY_USED(最不经常使用)
- 选择使用频率最低的执行器
7. LEAST_RECENTLY_USED(最近最久未使用)
- 选择最近最久未使用的执行器
8. FAILOVER(故障转移)
- 选择第一个执行器,失败后自动切换到下一个
- 适用于高可用场景
9. BUSYOVER(忙碌转移)
- 选择第一个执行器,如果忙碌则转移到下一个
10. SHARDING_BROADCAST(分片广播)
所有执行器都执行
适用于分片任务
单机部署:使用FIRST或LAST
负载均衡:使用ROUND或RANDOM
高可用:使用FAILOVER
分片任务:使用SHARDING_BROADCAST
参数相关:使用CONSISTENT_HASH
9. 失败重试与告警
在任务配置中设置"失败重试次数":
// 任务配置
失败重试次数: 3任务执行失败后,会自动重试指定次数。
邮件告警:
- 在任务配置中填写"报警邮件"
- 任务执行失败后,会发送告警邮件
告警邮件配置:
在调度中心配置文件中配置邮件服务器:
### 邮件配置
spring.mail.host=smtp.qq.com
spring.mail.port=587
spring.mail.username=your-email@qq.com
spring.mail.password=your-password
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true可以通过实现XxlJobLogCallback接口自定义告警逻辑:
@Component
public class CustomAlert implements XxlJobLogCallback {
@Override
public void callback(XxlJobLog xxlJobLog) {
if (xxlJobLog.getHandleCode() != 200) {
// 发送自定义告警
sendAlert(xxlJobLog);
}
}
private void sendAlert(XxlJobLog log) {
// 实现告警逻辑
}
}10. 动态分片
分片是将一个大任务拆分成多个小任务,由多个执行器并行执行,提高处理效率。
@Component
public class ShardingJob {
@XxlJob("shardingJobHandler")
public void shardingJobHandler() {
// 获取分片参数
int shardIndex = XxlJobHelper.getShardIndex();
int shardTotal = XxlJobHelper.getShardTotal();
// 获取待处理数据
List<String> dataList = getDataList();
// 计算当前分片需要处理的数据范围
int dataSize = dataList.size();
int perShard = (dataSize + shardTotal - 1) / shardTotal;
int start = shardIndex * perShard;
int end = Math.min(start + perShard, dataSize);
// 处理当前分片的数据
for (int i = start; i < end; i++) {
processData(dataList.get(i));
}
}
private List<String> getDataList() {
// 从数据库或其他数据源获取数据
return Arrays.asList("data1", "data2", "data3", "data4", "data5");
}
private void processData(String data) {
logger.info("处理数据: {}", data);
// 处理逻辑
}
}在任务配置中:
- 路由策略选择:
SHARDING_BROADCAST - 所有执行器都会执行,但处理不同的数据分片
- 确保数据可以被均匀分片
- 避免分片之间的数据依赖
- 注意分片失败的处理
- 合理设置分片数量
11. 与Spring Boot集成
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>2.4.0</version>
</dependency># application.yml
xxl:
job:
admin:
addresses: http://127.0.0.1:8080/xxl-job-admin
executor:
appname: xxl-job-executor
port: 9999
logpath: /data/applogs/xxl-job/jobhandler
logretentiondays: 30@Configuration
public class XxlJobConfig {
@Value("${xxl.job.admin.addresses}")
private String adminAddresses;
@Value("${xxl.job.executor.appname}")
private String appname;
@Value("${xxl.job.executor.port}")
private int port;
@Bean
public XxlJobSpringExecutor xxlJobExecutor() {
XxlJobSpringExecutor executor = new XxlJobSpringExecutor();
executor.setAdminAddresses(adminAddresses);
executor.setAppname(appname);
executor.setPort(port);
return executor;
}
}@Component
public class SpringBootJob {
@XxlJob("springBootJobHandler")
public void execute() {
// 业务逻辑
}
}12. 监控与运维
执行器状态:
- 在线:执行器已注册到调度中心
- 离线:执行器未注册或已下线
执行器信息:
- 执行器地址
- 注册时间
- 最后心跳时间
任务执行统计:
- 执行次数
- 成功次数
- 失败次数
- 成功率
- 平均执行时长
任务执行日志:
- 执行时间
- 执行状态
- 执行时长
- 日志内容
调度中心提供调度报表功能,可以查看:
- 任务调度统计
- 任务执行成功率
- 任务执行时长分布
- 执行器负载情况
执行器日志:
- 日志文件存储在配置的logpath目录
- 日志文件命名格式:
jobhandler-{jobId}-{logId}.log - 支持日志查看和下载
调度中心日志:
- 调度日志存储在数据库中
- 可以通过Web界面查看
- 支持日志搜索和过滤
13. 最佳实践
任务职责单一:一个任务只做一件事
任务幂等性:任务可以重复执行而不影响结果
任务可监控:任务执行过程可监控、可追踪
任务可恢复:任务失败后可以恢复
任务可扩展:任务可以水平扩展
合理使用分片:大数据量任务使用分片并行处理
避免长时间任务:长时间任务拆分成多个短任务
合理设置超时时间:避免任务执行时间过长
优化数据库操作:批量操作、使用连接池
合理使用缓存:减少重复计算
调度中心集群:部署多个调度中心实例
执行器集群:部署多个执行器实例
数据库主从:使用数据库主从复制
任务失败重试:配置合理的重试次数
监控告警:配置完善的监控和告警
访问控制:使用强密码,限制访问IP
数据加密:敏感数据加密存储
日志脱敏:日志中不包含敏感信息
权限管理:合理分配用户权限
定期备份:定期备份数据库和配置
14. 常见问题
**问题:**执行器启动后无法注册到调度中心
解决方案:
- 检查执行器配置的admin地址是否正确
- 检查网络连接是否正常
- 检查调度中心是否正常运行
- 检查执行器appname是否与调度中心配置一致
**问题:**任务执行失败,查看日志显示异常
解决方案:
- 查看执行日志,定位错误原因
- 检查任务代码是否有异常
- 检查任务参数是否正确
- 检查执行器资源是否充足
**问题:**任务配置后不执行
解决方案:
- 检查任务是否已启动
- 检查Cron表达式是否正确
- 检查执行器是否在线
- 检查任务是否被暂停
**问题:**分片任务处理的数据有重复
解决方案:
- 检查分片逻辑是否正确
- 确保分片边界计算正确
- 使用数据库锁避免重复处理
- 使用分布式锁控制并发
**问题:**任务执行时间超过配置的超时时间
解决方案:
- 优化任务执行逻辑,提高执行效率
- 增加任务超时时间配置
- 将大任务拆分成多个小任务
- 使用异步处理提高效率
15. 总结与进阶
通过本教程,你已经掌握了:
- ✅ xxl-job的基本概念和架构
- ✅ 调度中心和执行器的部署配置
- ✅ 任务的开发和管理
- ✅ 各种任务类型的使用
- ✅ 路由策略和分片任务
- ✅ 监控和运维
源码学习
- 调度中心调度逻辑
- 执行器注册机制
- 任务执行流程
高级特性
- 任务依赖
- 任务编排
- 动态任务
性能优化
- 调度性能优化
- 执行器性能优化
- 数据库优化
扩展开发
- 自定义路由策略
- 自定义告警方式
- 自定义任务类型
- 官方文档:https://www.xuxueli.com/xxl-job/
- GitHub:https://github.com/xuxueli/xxl-job
- 社区:https://www.xuxueli.com/xxl-job/
- 多实践:通过实际项目练习
- 多思考:理解设计原理
- 多优化:关注性能优化
- 多交流:参与社区讨论
结语
xxl-job是一个功能强大、易于使用的分布式任务调度平台。通过本教程的学习,相信你已经掌握了xxl-job的核心功能和使用方法。
记住:
- 多实践:理论结合实践,多写代码
- 多思考:理解设计原理,不要死记硬背
- 多优化:关注性能,优化任务执行
- 多学习:关注社区,持续学习
祝你学习愉快,编程顺利! 🚀
本教程由Java突击队学习社区编写,如有问题欢迎反馈。