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

相关文章

Spring Security简介、使用与最佳实践

《SpringSecurity简介、使用与最佳实践》SpringSecurity是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架,本文给大家介绍SpringSec... 目录一、如何理解 Spring Security?—— 核心思想二、如何在 Java 项目中使用?——

防止Linux rm命令误操作的多场景防护方案与实践

《防止Linuxrm命令误操作的多场景防护方案与实践》在Linux系统中,rm命令是删除文件和目录的高效工具,但一旦误操作,如执行rm-rf/或rm-rf/*,极易导致系统数据灾难,本文针对不同场景... 目录引言理解 rm 命令及误操作风险rm 命令基础常见误操作案例防护方案使用 rm编程 别名及安全删除

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

PHP应用中处理限流和API节流的最佳实践

《PHP应用中处理限流和API节流的最佳实践》限流和API节流对于确保Web应用程序的可靠性、安全性和可扩展性至关重要,本文将详细介绍PHP应用中处理限流和API节流的最佳实践,下面就来和小编一起学习... 目录限流的重要性在 php 中实施限流的最佳实践使用集中式存储进行状态管理(如 Redis)采用滑动

ShardingProxy读写分离之原理、配置与实践过程

《ShardingProxy读写分离之原理、配置与实践过程》ShardingProxy是ApacheShardingSphere的数据库中间件,通过三层架构实现读写分离,解决高并发场景下数据库性能瓶... 目录一、ShardingProxy技术定位与读写分离核心价值1.1 技术定位1.2 读写分离核心价值二

Three.js构建一个 3D 商品展示空间完整实战项目

《Three.js构建一个3D商品展示空间完整实战项目》Three.js是一个强大的JavaScript库,专用于在Web浏览器中创建3D图形,:本文主要介绍Three.js构建一个3D商品展... 目录引言项目核心技术1. 项目架构与资源组织2. 多模型切换、交互热点绑定3. 移动端适配与帧率优化4. 可

深入浅出Spring中的@Autowired自动注入的工作原理及实践应用

《深入浅出Spring中的@Autowired自动注入的工作原理及实践应用》在Spring框架的学习旅程中,@Autowired无疑是一个高频出现却又让初学者头疼的注解,它看似简单,却蕴含着Sprin... 目录深入浅出Spring中的@Autowired:自动注入的奥秘什么是依赖注入?@Autowired

MySQL分库分表的实践示例

《MySQL分库分表的实践示例》MySQL分库分表适用于数据量大或并发压力高的场景,核心技术包括水平/垂直分片和分库,需应对分布式事务、跨库查询等挑战,通过中间件和解决方案实现,最佳实践为合理策略、备... 目录一、分库分表的触发条件1.1 数据量阈值1.2 并发压力二、分库分表的核心技术模块2.1 水平分

JWT + 拦截器实现无状态登录系统

《JWT+拦截器实现无状态登录系统》JWT(JSONWebToken)提供了一种无状态的解决方案:用户登录后,服务器返回一个Token,后续请求携带该Token即可完成身份验证,无需服务器存储会话... 目录✅ 引言 一、JWT 是什么? 二、技术选型 三、项目结构 四、核心代码实现4.1 添加依赖(pom

SpringBoot集成XXL-JOB实现任务管理全流程

《SpringBoot集成XXL-JOB实现任务管理全流程》XXL-JOB是一款轻量级分布式任务调度平台,功能丰富、界面简洁、易于扩展,本文介绍如何通过SpringBoot项目,使用RestTempl... 目录一、前言二、项目结构简述三、Maven 依赖四、Controller 代码详解五、Service