XXL-JOB实践:从零开始构建你的任务调度系统

2024-09-06 19:52

本文主要是介绍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实践:从零开始构建你的任务调度系统的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1142962

相关文章

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

golang内存对齐的项目实践

《golang内存对齐的项目实践》本文主要介绍了golang内存对齐的项目实践,内存对齐不仅有助于提高内存访问效率,还确保了与硬件接口的兼容性,是Go语言编程中不可忽视的重要优化手段,下面就来介绍一下... 目录一、结构体中的字段顺序与内存对齐二、内存对齐的原理与规则三、调整结构体字段顺序优化内存对齐四、内

在不同系统间迁移Python程序的方法与教程

《在不同系统间迁移Python程序的方法与教程》本文介绍了几种将Windows上编写的Python程序迁移到Linux服务器上的方法,包括使用虚拟环境和依赖冻结、容器化技术(如Docker)、使用An... 目录使用虚拟环境和依赖冻结1. 创建虚拟环境2. 冻结依赖使用容器化技术(如 docker)1. 创

CentOS系统Maven安装教程分享

《CentOS系统Maven安装教程分享》本文介绍了如何在CentOS系统中安装Maven,并提供了一个简单的实际应用案例,安装Maven需要先安装Java和设置环境变量,Maven可以自动管理项目的... 目录准备工作下载并安装Maven常见问题及解决方法实际应用案例总结Maven是一个流行的项目管理工具

C++实现封装的顺序表的操作与实践

《C++实现封装的顺序表的操作与实践》在程序设计中,顺序表是一种常见的线性数据结构,通常用于存储具有固定顺序的元素,与链表不同,顺序表中的元素是连续存储的,因此访问速度较快,但插入和删除操作的效率可能... 目录一、顺序表的基本概念二、顺序表类的设计1. 顺序表类的成员变量2. 构造函数和析构函数三、顺序表

python实现简易SSL的项目实践

《python实现简易SSL的项目实践》本文主要介绍了python实现简易SSL的项目实践,包括CA.py、server.py和client.py三个模块,文中通过示例代码介绍的非常详细,对大家的学习... 目录运行环境运行前准备程序实现与流程说明运行截图代码CA.pyclient.pyserver.py参

使用C++实现单链表的操作与实践

《使用C++实现单链表的操作与实践》在程序设计中,链表是一种常见的数据结构,特别是在动态数据管理、频繁插入和删除元素的场景中,链表相比于数组,具有更高的灵活性和高效性,尤其是在需要频繁修改数据结构的应... 目录一、单链表的基本概念二、单链表类的设计1. 节点的定义2. 链表的类定义三、单链表的操作实现四、

nginx-rtmp-module构建流媒体直播服务器实战指南

《nginx-rtmp-module构建流媒体直播服务器实战指南》本文主要介绍了nginx-rtmp-module构建流媒体直播服务器实战指南,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有... 目录1. RTMP协议介绍与应用RTMP协议的原理RTMP协议的应用RTMP与现代流媒体技术的关系2

Spring Boot统一异常拦截实践指南(最新推荐)

《SpringBoot统一异常拦截实践指南(最新推荐)》本文介绍了SpringBoot中统一异常处理的重要性及实现方案,包括使用`@ControllerAdvice`和`@ExceptionHand... 目录Spring Boot统一异常拦截实践指南一、为什么需要统一异常处理二、核心实现方案1. 基础组件

SpringBoot项目中Maven剔除无用Jar引用的最佳实践

《SpringBoot项目中Maven剔除无用Jar引用的最佳实践》在SpringBoot项目开发中,Maven是最常用的构建工具之一,通过Maven,我们可以轻松地管理项目所需的依赖,而,... 目录1、引言2、Maven 依赖管理的基础概念2.1 什么是 Maven 依赖2.2 Maven 的依赖传递机