1. 为什么需要任务调度系统
在现代分布式系统中,定时任务和异步任务处理是几乎每个业务系统都会遇到的需求。传统的单机定时任务方案(如Java自带的Timer、ScheduledExecutorService)在分布式环境下会面临几个核心问题:
- 任务重复执行:多个实例同时运行同一个任务
- 任务丢失:实例宕机导致任务中断
- 缺乏可视化管控:无法直观查看任务执行状态
- 动态调整困难:修改任务需要重启应用
XXL-JOB正是为解决这些问题而生的分布式任务调度平台。它通过中心化的调度器和执行器分离架构,提供了以下核心能力:
- 动态任务管理:支持CRUD操作,无需重启服务
- 故障转移:自动识别下线节点并重新调度
- 日志追踪:完整记录每次任务执行详情
- 路由策略:支持轮询、随机、故障转移等调度算法
- 阻塞处理:提供串行、丢弃后续等策略
提示:XXL-JOB的调度中心和执行器采用HTTP通信,这意味着它们可以部署在不同网络环境中,只要保持网络连通即可。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与基础配置
2.1 调度中心部署
首先需要部署XXL-JOB的调度中心,这是整个系统的控制台:
bash复制# 从GitHub获取最新release包
wget https://github.com/xuxueli/xxl-job/releases/download/v2.3.1/xxl-job-admin-2.3.1.tar.gz
tar -zxvf xxl-job-admin-2.3.1.tar.gz
解压后修改配置文件application.properties:
properties复制# 数据库配置(需提前创建数据库)
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?useUnicode=true
spring.datasource.username=root
spring.datasource.password=123456
# 报警邮箱配置
spring.mail.host=smtp.163.com
spring.mail.username=yourmail@163.com
spring.mail.password=yourpassword
启动后访问http://localhost:8080/xxl-job-admin,默认账号admin/123456。
2.2 SpringBoot项目初始化
创建标准的SpringBoot项目,添加依赖:
xml复制<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>2.3.1</version>
</dependency>
配置执行器参数(application.yml):
yaml复制xxl:
job:
admin:
addresses: http://127.0.0.1:8080/xxl-job-admin
executor:
appname: xxl-job-executor-sample
address:
ip:
port: 9999
logpath: /data/applogs/xxl-job/jobhandler
logretentiondays: 30
accessToken:
注意:port不要与现有服务冲突,logpath需要有写入权限
3. 任务开发与注册
3.1 编写任务处理器
创建具体的任务处理类,实现IJobHandler接口:
java复制@Component
public class DemoJobHandler extends IJobHandler {
@Override
public ReturnT<String> execute(String param) throws Exception {
XxlJobLogger.log("任务开始执行,参数:" + param);
try {
// 业务逻辑
for(int i=0; i<5; i++){
XxlJobLogger.log("处理中..." + i);
Thread.sleep(1000);
}
return ReturnT.SUCCESS;
} catch (Exception e) {
XxlJobLogger.log(e);
return ReturnT.FAIL;
}
}
}
关键点说明:
XxlJobLogger.log用于记录执行日志,可在控制台查看- 返回
ReturnT.SUCCESS/FAIL标记任务状态 - 参数
param接收调度中心传入的参数
3.2 注册任务处理器
在配置类中注册处理器:
java复制@Configuration
public class XxlJobConfig {
@Value("${xxl.job.admin.addresses}")
private String adminAddresses;
@Bean
public XxlJobSpringExecutor xxlJobExecutor() {
XxlJobSpringExecutor xxlJobExecutor = new XxlJobSpringExecutor();
xxlJobExecutor.setAdminAddresses(adminAddresses);
xxlJobExecutor.setAppname("xxl-job-executor-sample");
xxlJobExecutor.setPort(9999);
return xxlJobExecutor;
}
}
4. 调度中心配置实战
4.1 创建执行器
登录调度中心,进入"执行器管理":
- 点击新增
- 填写AppName(与配置文件中一致)
- 选择注册方式:推荐自动注册
- 保存后等待执行器自动注册
4.2 配置任务
进入"任务管理"创建新任务:
| 配置项 | 示例值 | 说明 |
|---|---|---|
| 执行器 | xxl-job-executor-sample | 选择刚创建的执行器 |
| 任务描述 | 示例任务 | 业务描述 |
| 路由策略 | 轮询 | 多实例时生效 |
| Cron表达式 | 0 0/1 * * * ? | 每分钟执行一次 |
| 运行模式 | BEAN | 对应Java代码方式 |
| JobHandler | demoJobHandler | 类名首字母小写 |
| 任务参数 | test=123 | 会传入execute方法 |
| 阻塞处理策略 | 单机串行 | 防止任务堆积 |
4.3 任务监控
任务运行后可以在"调度日志"中查看:
- 绿色标记成功执行
- 红色标记失败任务
- 点击"执行日志"查看详细日志输出
5. 高级特性与最佳实践
5.1 分片广播任务
适用于大数据量并行处理场景:
java复制public ReturnT<String> execute(String param) {
// 获取分片参数
ShardingUtil.ShardingVO shardingVO = ShardingUtil.getShardingVo();
XxlJobLogger.log("分片参数:当前分片={}, 总分片={}",
shardingVO.getIndex(), shardingVO.getTotal());
// 根据分片处理数据
List<Long> dataList = fetchData();
for(int i=0; i<dataList.size(); i++){
if(i % shardingVO.getTotal() == shardingVO.getIndex()){
processItem(dataList.get(i));
}
}
return ReturnT.SUCCESS;
}
5.2 父子任务依赖
通过任务参数传递上下文:
java复制// 父任务
public ReturnT<String> parentJob(String param) {
String childParam = "parentId=" + System.currentTimeMillis();
return new ReturnT<>(childParam);
}
// 子任务(通过参数获取父任务结果)
public ReturnT<String> childJob(String param) {
String parentId = param.split("=")[1];
// 处理逻辑...
}
5.3 动态参数传递
调度中心支持多种参数来源:
- 固定值
- GLUE代码
- 命令行参数
- 其他任务返回值
推荐使用JSON格式传递复杂参数:
java复制// 调度中心参数
{"date":"2023-07-01","type":1}
// 代码解析
JSONObject params = JSON.parseObject(param);
String date = params.getString("date");
int type = params.getInteger("type");
6. 生产环境注意事项
6.1 性能调优
-
执行器线程池:默认200线程,根据机器配置调整
yaml复制xxl: job: executor: maxPoolSize: 300 -
数据库优化:定期清理日志表
sql复制DELETE FROM xxl_job_log WHERE trigger_time < DATE_SUB(NOW(), INTERVAL 30 DAY);
6.2 高可用部署
- 调度中心集群:部署多个实例,Nginx负载均衡
- 执行器去重:相同AppName的执行器会自动负载均衡
- 数据库主从:MySQL配置主从复制
6.3 常见问题排查
-
执行器未注册
- 检查网络连通性
- 验证AppName一致性
- 查看执行器日志
-
任务一直运行中
- 检查是否忘记返回SUCCESS/FAIL
- 确认没有线程阻塞
-
日志不显示
- 检查logpath权限
- 确认使用了XxlJobLogger
我在实际使用中发现,对于耗时较长的任务,建议:
- 添加心跳检测机制
- 实现任务进度上报
- 设置合理的超时时间(调度中心可配置)
