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 Optional的使用技巧与最佳实践

《JavaOptional的使用技巧与最佳实践》在Java中,Optional是用于优雅处理null的容器类,其核心目标是显式提醒开发者处理空值场景,避免NullPointerExce... 目录一、Optional 的核心用途二、使用技巧与最佳实践三、常见误区与反模式四、替代方案与扩展五、总结在 Java

Spring Boot循环依赖原理、解决方案与最佳实践(全解析)

《SpringBoot循环依赖原理、解决方案与最佳实践(全解析)》循环依赖指两个或多个Bean相互直接或间接引用,形成闭环依赖关系,:本文主要介绍SpringBoot循环依赖原理、解决方案与最... 目录一、循环依赖的本质与危害1.1 什么是循环依赖?1.2 核心危害二、Spring的三级缓存机制2.1 三

使用Python构建一个Hexo博客发布工具

《使用Python构建一个Hexo博客发布工具》虽然Hexo的命令行工具非常强大,但对于日常的博客撰写和发布过程,我总觉得缺少一个直观的图形界面来简化操作,下面我们就来看看如何使用Python构建一个... 目录引言Hexo博客系统简介设计需求技术选择代码实现主框架界面设计核心功能实现1. 发布文章2. 加

Python 中的 with open文件操作的最佳实践

《Python中的withopen文件操作的最佳实践》在Python中,withopen()提供了一个简洁而安全的方式来处理文件操作,它不仅能确保文件在操作完成后自动关闭,还能处理文件操作中的异... 目录什么是 with open()?为什么使用 with open()?使用 with open() 进行

利用Python快速搭建Markdown笔记发布系统

《利用Python快速搭建Markdown笔记发布系统》这篇文章主要为大家详细介绍了使用Python生态的成熟工具,在30分钟内搭建一个支持Markdown渲染、分类标签、全文搜索的私有化知识发布系统... 目录引言:为什么要自建知识博客一、技术选型:极简主义开发栈二、系统架构设计三、核心代码实现(分步解析

Python FastAPI+Celery+RabbitMQ实现分布式图片水印处理系统

《PythonFastAPI+Celery+RabbitMQ实现分布式图片水印处理系统》这篇文章主要为大家详细介绍了PythonFastAPI如何结合Celery以及RabbitMQ实现简单的分布式... 实现思路FastAPI 服务器Celery 任务队列RabbitMQ 作为消息代理定时任务处理完整

Linux系统中卸载与安装JDK的详细教程

《Linux系统中卸载与安装JDK的详细教程》本文详细介绍了如何在Linux系统中通过Xshell和Xftp工具连接与传输文件,然后进行JDK的安装与卸载,安装步骤包括连接Linux、传输JDK安装包... 目录1、卸载1.1 linux删除自带的JDK1.2 Linux上卸载自己安装的JDK2、安装2.1

Spring Boot 配置文件之类型、加载顺序与最佳实践记录

《SpringBoot配置文件之类型、加载顺序与最佳实践记录》SpringBoot的配置文件是灵活且强大的工具,通过合理的配置管理,可以让应用开发和部署更加高效,无论是简单的属性配置,还是复杂... 目录Spring Boot 配置文件详解一、Spring Boot 配置文件类型1.1 applicatio

一文详解如何从零构建Spring Boot Starter并实现整合

《一文详解如何从零构建SpringBootStarter并实现整合》SpringBoot是一个开源的Java基础框架,用于创建独立、生产级的基于Spring框架的应用程序,:本文主要介绍如何从... 目录一、Spring Boot Starter的核心价值二、Starter项目创建全流程2.1 项目初始化(

tomcat多实例部署的项目实践

《tomcat多实例部署的项目实践》Tomcat多实例是指在一台设备上运行多个Tomcat服务,这些Tomcat相互独立,本文主要介绍了tomcat多实例部署的项目实践,具有一定的参考价值,感兴趣的可... 目录1.创建项目目录,测试文China编程件2js.创建实例的安装目录3.准备实例的配置文件4.编辑实例的