XxlJob任务
SchedulerX 2.0兼容XXL-JOB任务接口,支持@XxlJob
新注解和@JobHandler
老注解方式,您不需要修改代码,即可将XXL-JOB任务在SchedulerX 2.0平台上进行调度。
背景信息
XXL-JOB是一个开箱即用的轻量级分布式任务调度系统,其核心设计目标是开发迅速、学习简单、轻量级、易扩展,在开源社区广泛流行,已在多家公司投入使用。XXL-JOB开源协议采用的是GPL,因此云厂商无法直接商业化托管该产品,各大中小企业需要自建,增加了学习成本、机器成本、人工运维成本。阿里巴巴商业化任务调度平台SchedulerX 2.0兼容XXL-JOB任务接口,您不需要修改一行代码,即可将XXL-JOB任务在SchedulerX 2.0平台上托管。
采用托管的XXL-JOB有以下优势:
免运维、低成本
自建XXL-JOB最少需要2个服务器和1个数据库支撑,而使用托管的XXL-JOB可以省去这些机器成本和人力运维成本。
海量任务、精准调度
开源XXL-JOB基于竞争数据库锁保证只有一个节点执行任务,对于数据库有压力。据统计,当任务超过1万,都是分钟级别的任务时,就会有比较明显的调度延时,如果是秒级别任务,延时就更加明显。SchedulerX 2.0采用分布式架构,不同的server调度不同的任务,且无锁竞争,真正实现可以水平扩展,可以支持百万级别任务调度。SchedulerX 2.0针对秒级别任务低延时的特性,采用了专门的架构,占用资源极低,可以作为实时业务的秒级别调度场景。另外,SchedulerX 2.0还支持一次性任务,可以指定未来某个时刻执行一次任务,执行完任务自动销毁,可以作为定时通知、订单定时关闭等场景。
高级特性
工作流:通过可视化的工作流进行任务编排。
限流:可抢占的任务优先级队列。
资源隔离:支持命名空间和应用级别的资源隔离,支持多租户权限管理。
高可用
SchedulerX 2.0采用高可用架构,任务多备份机制,经历过阿里集团多年双十一、容灾演练等场景的考验,可以做到整个集群挂掉任意2个节点或者任意一个机房断电,任务调度都不会受到影响。
商业化报警运维
SchedulerX 2.0除了兼容XXL-JOB的邮件报警和基本运维操作,还提供了商业化报警和运维功能:
报警:通过钉钉群、短信、电话等发送通知。
运维:支持原地重跑、重刷数据、标记成功、查看堆栈、停止任务等操作。
与开源XXL-JOB的区别
与开源XXL-JOB的区别入如下表所示。
功能 | 开源XXL-JOB | SchedulerX为底座的XXL-JOB任务 |
Java任务 | ||
Go任务 | ||
脚本任务 | ||
HTTP任务 | ||
单机 | ||
分片广播 | ||
MapReduce模型 | ||
路由策略 | 第一个、最后一个、轮询、随机等 | 轮询 |
定时 | cron | cron、fixed_rate、fixed_delay、one_time |
工作流 | ||
运维操作 | 运行一次、停止运行 | 运行一次、停止运行、原地重跑、重刷数据、标记成功 |
日志查询 | 日志存在executor本地,机器挂了日志丢失 | 日志存储在阿里云日志服务,保留最近2周,支持搜索 |
可观测 | 历史记录、运行大盘 | 历史记录、运行大盘、操作记录、查看堆栈、链路追踪 |
报警监控 | 邮件 | 邮件、钉钉、飞书、企业微信、自定义WebHook、短信、电话 |
高可用及容灾 | 需要自己维护数据库和Server的容灾 | 默认支持同城多机房容灾 |
用户权限 | 用户隔离,通过账号密码登录 | 支持单点登录、主子账号、角色、RAM精细化权限管理 |
优雅下线 | ||
全链路灰度 | ||
限流 |
接入配置
应用的pom.xml文件做如下变更:将
com.xuxueli:XXL-JOB-core
的依赖去除,增加SchedulerX客户端的依赖和com.aliyun:schedulerx2-plugin-xxljob
插件。因为XXL-JOB在2.3.x版本重构了接口,请根据XXL-JOB的版本选择不同的接入方式,以
schedulerx2-spring-boot-starter
应用为例,配置内容如下:2.3.x版本接入,请参考Demo。
schedulerx2.version
使用客户端最新版本,例如<version>1.11.5</version>
。更多信息,请参见客户端发布记录。<!-- 注释xxl-job-core --> <!-- <dependency> <groupId>com.xuxueli</groupId> <artifactId>xxl-job-core</artifactId> <version>${project.parent.version}</version> </dependency> --> <!-- 添加schedulerx依赖 --> <dependency> <groupId>com.aliyun.schedulerx</groupId> <artifactId>schedulerx2-spring-boot-starter</artifactId> <version>${schedulerx2.version}</version> </dependency> <!-- 新增schedulerx2-plugin-xxljob --> <dependency> <groupId>com.aliyun.schedulerx</groupId> <artifactId>schedulerx2-plugin-xxljob</artifactId> <version>2.3.5</version> </dependency>
2.2.x以下版本接入,请参考Demo。
schedulerx2.version
使用客户端的最新版本,例如<version>1.11.5</version>
。更多信息,请参见客户端发布记录。<!-- 注释xxl-job-core --> <!-- <dependency> <groupId>com.xuxueli</groupId> <artifactId>xxl-job-core</artifactId> <version>${project.parent.version}</version> </dependency> --> <!-- 添加schedulerx依赖 --> <dependency> <groupId>com.aliyun.schedulerx</groupId> <artifactId>schedulerx2-spring-boot-starter</artifactId> <version>${schedulerx2.version}</version> </dependency> <!-- 新增schedulerx2-plugin-xxljob --> <dependency> <groupId>com.aliyun.schedulerx</groupId> <artifactId>schedulerx2-plugin-xxljob</artifactId> <version>2.2.4</version> </dependency>
agent.properties文件添加如下配置,具体操作,请参见Agent接入(脚本或HTTP任务)。
spring.schedulerx2.endpoint=192.xx.xx.xx spring.schedulerx2.namespace=20e90ffc**** spring.schedulerx2.groupId=679xxx spring.schedulerx2.appKey=71BCC0Exxx
使用Xxljob方法创建任务
参考开源XXL-JOB-executor-sample-springboot
工程,创建方法任务,示例代码如下:
/**
* 简单任务示例(Bean模式)
*/
@XxlJob("demoJobHandler")
public ReturnT<String> demoJobHandler(String param) throws Exception {
System.out.println("XXL-JOB, " + param);
return ReturnT.SUCCESS;
}
使用JobHandler方法创建任务
示例代码如下:
@JobHandler(value="HelloJobHandler")
@Componentpublic class HelloJobHandler extends IJobHandler {
@Override
public ReturnT<String> execute(String param) throws Exception {
System.out.println("HelloJobHandler: " + param);
return SUCCESS;
}
}
使用分片广播的方式创建任务
以XxlJob方法注解为例,示例代码如下:
/**
* 分片广播任务
*/
@XxlJob("shardingJobHandler")
public ReturnT<String> shardingJobHandler(String param) throws Exception {
// 分片参数
int shardIndex = XxlJobContext.getXxlJobContext().getShardIndex();
int shardTotal = XxlJobContext.getXxlJobContext().getShardTotal();
XxlJobLogger.log("分片参数:当前分片序号 = {}, 总分片数 = {}", shardIndex, shardTotal);
System.out.println("分片参数:当前分片序号 ="+ shardIndex + ", 总分片数 = " + shardTotal);
// 业务逻辑
for (int i = 0; i < shardTotal; i++) {
if (i == shardIndex) {
System.out.println("第 " + i + " 片, 命中分片开始处理");
XxlJobLogger.log("第 {} 片, 命中分片开始处理", i);
} else {
XxlJobLogger.log("第 {} 片, 忽略", i);
}
}
return ReturnT.SUCCESS;
}