本文主要是介绍XXL-JOB实践:从零开始构建你的任务调度系统,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
目录
- 一、序言
- 1、系统组成
- 2、架构图
- 二、部署调度中心
- 1、下载源码
- 2、执行数据库脚本
- 3、修改application.properties配置文件
- 4、启动调度中心
- 三、部署执行器
- 1、引入依赖
- 2、执行器配置
- 2.1 XxlJobProperties属性文件
- 2.2 XxlJobConfig配置类
- 2.3 XxlJobHanlder作业处理器
- 2.4 application.yml
- 3、启动执行器
- 四、调度示例
- 1、添加执行器
- 2、添加任务
- 3、调度测试
一、序言
XXL-JOB
是一个分布式任务调度平台,部署方便,使用简单,开箱即用,目前已经有600多家公司线上已经接入。
1、系统组成
XXL-JOB
主要由两个模块组成,一个是调度中心,一个是执行器。
-
调度模块(调度中心):
负责管理调度信息,按照调度配置发出调度请求,自身不承担业务代码。调度系统与任务解耦,提高了系统可用性和稳定性,同时调度系统性能不再受限于任务模块。 -
执行模块(执行器):
负责接收调度请求并执行任务逻辑。任务模块专注于任务的执行等操作,开发和维护更加简单和高效。
2、架构图
主要特性如下:.
- 调度中心与执行器通过
自研RPC
进行通讯和调度。 - 调度中心多线程调度可以避免IO阻塞,支持
并行调度
。 - 多个执行器支持
故障转移(Failover)
执行器。 - 调度中心都支持
集群部署
,提高系统可用性(HA)。 - 支持调度过期处理 (如:服务重启,调度线程耗尽,上次调度持续阻塞导致下次调度过期)。
- 支持调度日志查看。
二、部署调度中心
调度中心的部署非常简单,开箱即用,详细说明参考:官方文档。
1、下载源码
建议下载最新的Release版本,我用的版本是2.4.1
。
2、执行数据库脚本
项目目录下有调度中心依赖的数据库表:doc/db/tables_xxl_job.sql
,直接执行即可,如下:
#
# XXL-JOB v2.4.1
# Copyright (c) 2015-present, xuxueli.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;CREATE TABLE `xxl_job_log`
(`id` bigint(20) NOT NULL AUTO_INCREMENT,`job_group` int(11) NOT NULL COMMENT '执行器主键ID',`job_id` int(11) NOT NULL COMMENT '任务,主键ID',`executor_address` varchar(255) DEFAULT NULL COMMENT '执行器地址,本次执行的地址',`executor_handler` varchar(255) DEFAULT NULL COMMENT '执行器任务handler',`executor_param` varchar(512) DEFAULT NULL COMMENT '执行器任务参数',`executor_sharding_param` varchar(20) DEFAULT NULL COMMENT '执行器任务分片参数,格式如 1/2',`executor_fail_retry_count` int(11) NOT NULL DEFAULT '0' COMMENT '失败重试次数',`trigger_time` datetime DEFAULT NULL COMMENT '调度-时间',`trigger_code` int(11) NOT NULL COMMENT '调度-结果',`trigger_msg` text COMMENT '调度-日志',`handle_time` datetime DEFAULT NULL COMMENT '执行-时间',`handle_code` int(11) NOT NULL COMMENT '执行-状态',`handle_msg` text COMMENT '执行-日志',`alarm_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '告警状态:0-默认、1-无需告警、2-告警成功、3-告警失败',PRIMARY KEY (`id`),KEY `I_trigger_time` (`trigger_time`),KEY `I_handle_code` (`handle_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;CREATE TABLE `xxl_job_log_report`
(`id` int(11) NOT NULL AUTO_INCREMENT,`trigger_day` datetime DEFAULT NULL COMMENT '调度-时间',`running_count` int(11) NOT NULL DEFAULT '0' COMMENT '运行中-日志数量',`suc_count` int(11) NOT NULL DEFAULT '0' COMMENT '执行成功-日志数量',`fail_count` int(11) NOT NULL DEFAULT '0' COMMENT '执行失败-日志数量',`update_time` datetime DEFAULT NULL,PRIMARY KEY (`id`),UNIQUE KEY `i_trigger_day` (`trigger_day`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;CREATE TABLE `xxl_job_logglue`
(`id` int(11) NOT NULL AUTO_INCREMENT,`job_id` int(11) NOT NULL COMMENT '任务,主键ID',`glue_type` varchar(50) DEFAULT NULL COMMENT 'GLUE类型',`glue_source` mediumtext COMMENT 'GLUE源代码',`glue_remark` varchar(128) NOT NULL COMMENT 'GLUE备注',`add_time` datetime DEFAULT NULL,`update_time` datetime DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;CREATE TABLE `xxl_job_registry`
(`id` int(11) NOT NULL AUTO_INCREMENT,`registry_group` varchar(50) NOT NULL,`registry_key` varchar(255) NOT NULL,`registry_value` varchar(255) NOT NULL,`update_time` datetime DEFAULT NULL,PRIMARY KEY (`id`),KEY `i_g_k_v` (`registry_group`,`registry_key`,`registry_value`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;CREATE TABLE `xxl_job_group`
(`id` int(11) NOT NULL AUTO_INCREMENT,`app_name` varchar(64) NOT NULL COMMENT '执行器AppName',`title` varchar(12) NOT NULL COMMENT '执行器名称',`address_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '执行器地址类型:0=自动注册、1=手动录入',`address_list` text COMMENT '执行器地址列表,多地址逗号分隔',`update_time` datetime DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;CREATE TABLE `xxl_job_user`
(`id` int(11) NOT NULL AUTO_INCREMENT,`username` varchar(50) NOT NULL COMMENT '账号',`password` varchar(50) NOT NULL COMMENT '密码',`role` tinyint(4) NOT NULL COMMENT '角色:0-普通用户、1-管理员',`permission` varchar(255) DEFAULT NULL COMMENT '权限:执行器ID列表,多个逗号分割',PRIMARY KEY (`id`),UNIQUE KEY `i_username` (`username`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;CREATE TABLE `xxl_job_lock`
(`lock_name` varchar(50) NOT NULL COMMENT '锁名称',PRIMARY KEY (`lock_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;INSERT INTO `xxl_job_user`(`id`, `username`, `password`, `role`, `permission`) VALUES (1, 'admin', 'e10adc3949ba59abbe56e057f20f883e', 1, NULL);
INSERT INTO `xxl_job_lock` ( `lock_name`) VALUES ( 'schedule_lock');
3、修改application.properties配置文件
直接修改数据源配置即可,下面的xxl.job.accessToken
配置为执行器与调度中心通讯的访问token,为可选配置。
4、启动调度中心
直接启动,浏览器输入http://localhost:8888/xxl-job-admin
进入登录页面,默认用户名/密码为admin/123456
。
三、部署执行器
1、引入依赖
<dependency><groupId>com.xuxueli</groupId><artifactId>xxl-job-core</artifactId><version>2.4.1</version></dependency>
2、执行器配置
2.1 XxlJobProperties属性文件
@Data
@ConfigurationProperties(prefix = "xxl.job")
public class XxlJobProperties {/*** 执行器通讯TOKEN [选填]:非空时启用,需要与调度中心的保持一致*/private String accessToken;/*** 调度中心信息*/private Admin admin;/*** 执行器信息*/private Executor executor;@Datapublic static class Admin {/*** 调度中心部署跟地址,如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册*/private String addresses;}@Datapublic static class Executor {/*** 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册*/private String appName;/*** 执行器注册 [选填]:优先使用该配置作为注册地址,为空时使用内嵌服务 ”IP:PORT“ 作为注册地址。从而更灵活的支持容器类型执行器动态IP和动态映射端口问题*/private String address;/*** 执行器IP [选填]:默认为空表示自动获取IP,多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯实用;地址信息用于 "执行器注册" 和 "调度中心请求并触发任务"*/private String ip;/*** 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口*/private Integer port;/*** 执行器运行日志文件存储磁盘路径 [选填] :zz需要对该路径拥有读写权限;为空则使用默认路径*/private String logPath;/*** 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能*/private Integer logRetentionDays;}
}
2.2 XxlJobConfig配置类
@Configuration
@EnableConfigurationProperties(XxlJobProperties.class)
public class XxlJobConfig {@Beanpublic XxlJobSpringExecutor xxlJobSpringExecutor(XxlJobProperties xxlJobProperties) {XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();xxlJobSpringExecutor.setAdminAddresses(xxlJobProperties.getAdmin().getAddresses());Executor executor = xxlJobProperties.getExecutor();xxlJobSpringExecutor.setAppname(executor.getAppName());xxlJobSpringExecutor.setAddress(executor.getAddress());xxlJobSpringExecutor.setIp(executor.getIp());xxlJobSpringExecutor.setPort(executor.getPort());xxlJobSpringExecutor.setLogPath(executor.getLogPath());xxlJobSpringExecutor.setLogRetentionDays(executor.getLogRetentionDays());xxlJobSpringExecutor.setAccessToken(xxlJobProperties.getAccessToken());return xxlJobSpringExecutor;}
}
2.3 XxlJobHanlder作业处理器
@Slf4j
@Component
public class XxlJobHanlder {@XxlJob("simpleJobHanlder")public void simpleJobHanlder() {log.info("Hello World!");// 可通过该工具类指定任务是否处理成功或者失败:XxlJobHelper.handleSuccess()或者XxlJobHelper.handleFail()XxlJobHelper.handleSuccess();}@XxlJob("paramJobHanlder")public void paramJobHanlder() {String jobParam = XxlJobHelper.getJobParam();log.info("paramJobHandler is executing, job param:{}, msg: Hello World! ",jobParam);XxlJobHelper.handleSuccess();}@XxlJob("shardingJobHandler")public void shardingJobHandler() {// 分片序号,即执行器编号int shardIndex = XxlJobHelper.getShardIndex();// 总分片数int sharTotal = XxlJobHelper.getShardTotal();log.info("分片参数:当前分片序号:{},总分片数:{}", shardIndex, sharTotal);// 模拟任务超时LockSupport.parkNanos(1000 * 1000 * 1000 * 5L);log.info("分片执行完毕");XxlJobHelper.handleSuccess();}
上面我们定义了3个作业处理器,分别是简单作业处理器,带作业参数的作业处理器和分片作业处理器。
XxlJobHelper
工具类提供了一些基本方法,比如指定任务调度为成功或者失败,获取作业和分片参数等。
2.4 application.yml
spring:application:name: xxl-job-executor
server:port: 8081
xxl:job:# 执行器通讯TOKEN [选填]:非空时启用accessToken: rXXZnXk8fsx8RIOtjLUT5koi4hzCMS0Dadmin:# 调度中心部署跟地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册addresses: http://localhost:8888/xxl-job-adminexecutor:# 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册app-name: xxl-job-executor# 执行器运行日志文件存储磁盘路径 [选填] :zz需要对该路径拥有读写权限;为空则使用默认路径log-path: logs/jobhandler# 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能log-retention-days: 30# 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口port: 9999# 执行器注册 [选填]:优先使用该配置作为注册地址,为空时使用内嵌服务 ”IP:PORT“ 作为注册地址。从而更灵活的支持容器类型执行器动态IP和动态映射端口问题address:# 执行器IP [选填]:默认为空表示自动获取IP,多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯实用;地址信息用于 "执行器注册" 和 "调度中心请求并触发任务"ip:
备注:
xxl.job.accessToken
的值必须与调度中心配置的token保持一致,不然会连不上调度中心。xxl.job.executor.app-name
的值为执行器名称,如果是自动注册,在控制台添加执行器时,需与该值保持一致。
xxl.job.executor.port
为执行器暴露的端口,调度中心将会通过该端口与执行器进行RPC调度。
3、启动执行器
启动执行器后,我们会发现三个作业处理器注册成功,并且执行器启动了内置服务器,并暴露9999
端口与调度中心通讯。
四、调度示例
1、添加执行器
在控制台执行器管理中我们需要手动添加执行器,这里的AppName
一定要与执行器xxl.job.executor.app-name
的值一致,不然自动注册会失败。
注册成功后我们可以看到执行器的地址和端口,如下:
2、添加任务
在控制台任务管理中可以直接新增任务,如下:
这里我们添加了两个任务,可以点击操作中的执行一次进行调度测试。
3、调度测试
(1) simpleJobHanlder测试
17:32:47.089 [xxl-job, EmbedServer bizThreadPool-626635208] INFO c.x.job.core.executor.XxlJobExecutor - >>>>>>>>>>> xxl-job regist JobThread success, jobId:2, handler:com.xxl.job.core.handler.impl.MethodJobHandler@116a2108[class com.universe.jobhanlder.XxlJobHanlder#simpleJobHanlder]
17:32:47.091 [xxl-job, JobThread-2-1725615167089] INFO c.universe.jobhanlder.XxlJobHanlder - Hello World!
(2) paramJobHanlder测试
这里我们是带了作业参数的,调度结果如下:
17:35:26.556 [xxl-job, EmbedServer bizThreadPool-412218852] INFO c.x.job.core.executor.XxlJobExecutor - >>>>>>>>>>> xxl-job regist JobThread success, jobId:3, handler:com.xxl.job.core.handler.impl.MethodJobHandler@5e8c34a0[class com.universe.jobhanlder.XxlJobHanlder#paramJobHanlder]
17:35:26.558 [xxl-job, JobThread-3-1725615326556] INFO c.universe.jobhanlder.XxlJobHanlder - paramJobHandler is executing, job param:{"name": "Nick"
}, msg: Hello World!
这篇关于XXL-JOB实践:从零开始构建你的任务调度系统的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!