• Spring Boot 整合xxl-job实现分布式定时任务


    xxl-job介绍

    XXL-JOB是一个分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。

    xxl是xxl-job的开发者大众点评的许雪里名称的拼音开头。

    设计思想

    • 将调度行为抽象形成“调度中心”公共平台,而平台自身并不承担业务逻辑,“调度中心”负责发起调度请求。

    • 将任务抽象成分散的JobHandler,交由“执行器”统一管理,“执行器”负责接收调度请求并执行对应的JobHandler中业务逻辑。

    因此,“调度”和“任务”两部分可以相互解耦,提高系统整体稳定性和扩展性;

    系统组成

    • 调度模块(调度中心)
      负责管理调度信息,按照调度配置发出调度请求,自身不承担业务代码。调度系统与任务解耦,提高了系统可用性和稳定性,同时调度系统性能不再受限于任务模块;
      支持可视化、简单且动态的管理调度信息,包括任务新建,更新,删除,GLUE开发和任务报警等,所有上述操作都会实时生效,同时支持监控调度结果以及执行日志,支持执行器Failover。
    • 执行模块(执行器)
      负责接收调度请求并执行任务逻辑。任务模块专注于任务的执行等操作,开发和维护更加简单和高效;
      接收“调度中心”的执行请求、终止请求和日志请求等。

    总体架构图

    在这里插入图片描述

    执行流程

    在这里插入图片描述

    原理分析

    1、执行器的注册和发现
    执行器的注册和发现主要是关系两张表:

    • xxl_job_group:每个服务注册的实例列表。
    • xxl_job_registry:执行器的实例表,保存实例信息和心跳信息。

    执行器启动线程每隔30秒向注册表xxl_job_registry请求一次,更新执行器的心跳信息,调度中心启动 线程每隔30秒检测一次xxl_job_registry,将超过90秒还没有收到心跳的实例信息从xxl_job_registry删除,并更新xxl_job_group服务的实例列表信息。

    2、调度中心调用执行器

    调度中心的操作:

    调度中心通过循环不停的:

    关闭自动提交事务

    利用mysql的悲观锁,其他事务无法进入

    select * from xxl_job_lock where lock_name = 'schedule_lock' for update
    
    • 1

    3、读取数据库中的xxl_job_info:记录定时任务的相关信息,该表中有trigger_next_time字段表示下一次任务的触发时间。拿到距离当前时间5s内的任务列表,分为三种情况处理:

    • 对于当前时间-任务的下一次触发时间>5,直接跳过不执行,重置trigger_next_time的时间。(超过5s)

    • 对于任务的下一次触发时间<当前时间<任务的下一次触发时间+5的任务(不超过5s的):

    ​ 开线程处理执行触发逻辑,根据当前时间更新下一次任务触发时间

    ​ 如果新的任务下一次触发时间-当前时间<5,放到时间轮中,时间轮是一个map:

     private volatile static Map<Integer, List<Integer>> ringData = new ConcurrentHashMap<>();
    
    • 1

    ​ 根据新的任务下一次触发时间更新下下一次任务触发时间

    • 对于任务的下一次触发时间>当前时间,将其放入时间轮中,根据任务下一次触发时间更新下下一次任务触发时间

    4、commit提交事务,同时释放排他锁

    5、执行器的操作:

    • 执行器接收到调度中心的调度信息,将调度信息放到对应的任务的等待队列中
    • 执行器的任务处理线程从任务队列中取出调度信息,执行业务逻辑,将结果放入一个公共的等待队列中(每个任务都有一个单独的处理线程和等待队列,任务信息放入该队列中)
    • 执行器有一个专门的回调线程定时批量从结果队列中取出任务结果,并且回调告知调度中心

    关于更多的详细介绍推荐阅读官方文档[^1]:

    https://www.xuxueli.com/xxl-job/

    xxl-job快速入门

    Spring Boot集成XXL-JOB 主要需要配置以下两项:

    • 配置运行调度中心(xxl-job-admin)
    • 配置运行执行器项目

    项目准备及脚本初始化

    从如下代码仓库中下载xxl-job-admin

    https://gitee.com/xuxueli0323/xxl-job

    在这里插入图片描述

    下载完成后使用IDEA打开该项目,进行项目构建。

    构建完成后,执行项目的doc/db文件夹下面的tables_xxl_job.sql数据库脚本,进行调度数据库表的初始化。

    在这里插入图片描述

    1699783089231)

    数据表说明
    xxl_job_lock任务调度锁表
    xxl_job_group执行器信息表,维护任务执行器信息
    xxl_job_info调度扩展信息表: 用于保存XXL-JOB调度任务的扩展信息,如任务分组、任务名、机器地址、执行器、执行入参和报警邮件等等
    xxl_job_log调度日志表: 用于保存XXL-JOB任务调度的历史信息,如调度结果、执行结果、调度入参、调度机器和执行器等等
    xxl_job_log_report调度日志报表:用户存储XXL-JOB任务调度日志的报表,调度中心报表功能页面会用到
    xxl_job_logglue任务GLUE日志:用于保存GLUE更新历史,用于支持GLUE的版本回溯功能
    xxl_job_registry执行器注册表,维护在线的执行器和调度中心机器地址信息
    xxl_job_user系统用户表

    配置调度中心

    修改配置文件,主要配置datasource 以及 email

    application.properties

    ### web
    server.port=9100
    
    ### xxl-job, datasource
    spring.datasource.url=jdbc:mysql://127.0.0.1:3306/ballcat?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
    spring.datasource.username=xxkfz
    spring.datasource.password=xxkfz
    spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    注:由于小编默认8080端口被占用,这里修改了一下项目的端口号:

    server.port=9100

    配置完成后启动下面主启动类,启动项目:

    XxlJobAdminApplication.java
    
    • 1

    启动完成后,访问地址为:http://localhost:8080/xxl-job-admin,默认的用户为 admin,密码 123456,即可进入后台管理系统页面。

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    至此,调度中心配置完成,接下来进行执行器的项目配置。

    配置执行器项目(整合Spring Boot项目)

    该部分官方已经给出具体的案例,因此我们只需对本案例进行整合或修改即可。

    官方案例对应工程:xxl-job-executor-sample-springboot

    引入依赖
    
    
       com.xuxueli
       xxl-job-core
       ${project.parent.version}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    注:此处版本要与 xxl-job-admin 中版本保持一致!

    引入配置类

    XxlJobConfig.java

    我们直接从xxl-job-executor-sample-springboot项目中把XxlJobConfig.java配置类复制到你的项目中即可,不需要进行任何的修改。

    @Configuration
    public class XxlJobConfig {
        private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);
    
        @Value("${xxl.job.admin.addresses}")
        private String adminAddresses;
    
        @Value("${xxl.job.accessToken}")
        private String accessToken;
    
        @Value("${xxl.job.executor.appname}")
        private String appname;
    
        @Value("${xxl.job.executor.address}")
        private String address;
    
        @Value("${xxl.job.executor.ip}")
        private String ip;
    
        @Value("${xxl.job.executor.port}")
        private int port;
    
        @Value("${xxl.job.executor.logpath}")
        private String logPath;
    
        @Value("${xxl.job.executor.logretentiondays}")
        private int logRetentionDays;
    
    
        @Bean
        public XxlJobSpringExecutor xxlJobExecutor() {
            logger.info(">>>>>>>>>>> xxl-job config init.");
            XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
            xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
            xxlJobSpringExecutor.setAppname(appname);
            xxlJobSpringExecutor.setAddress(address);
            xxlJobSpringExecutor.setIp(ip);
            xxlJobSpringExecutor.setPort(port);
            xxlJobSpringExecutor.setAccessToken(accessToken);
            xxlJobSpringExecutor.setLogPath(logPath);
            xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
    
            return xxlJobSpringExecutor;
        }
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    修改项目配置文件
    # web port
    server.port=8098
    # no web
    #spring.main.web-environment=false
    
    # log config
    logging.config=classpath:logback.xml
    
    
    ### xxl-job admin address list, such as "http://address" or "http://address01,http://address02"
    xxl.job.admin.addresses=http://127.0.0.1:9100/xxl-job-admin
    
    ### xxl-job, access token
    xxl.job.accessToken=default_token
    
    ### xxl-job executor appname
    xxl.job.executor.appname=xxkfz-job-fileExport
    ### xxl-job executor registry-address: default use address to registry , otherwise use ip:port if address is null
    xxl.job.executor.address=
    ### xxl-job executor server-info
    xxl.job.executor.ip=
    xxl.job.executor.port=9999
    ### xxl-job executor log-path
    xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
    ### xxl-job executor log-retention-days
    xxl.job.executor.logretentiondays=30
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    编写测试类

    TaskConfig.java

    @Component
    @Slf4j
    public class TaskConfig {
    
        @XxlJob("fileExport")
        public void execute() {
            log.debug("文件开始导出了......");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    任务配置

    新增执行器

    在这里插入图片描述

    配置任务

    在这里插入图片描述

    测试

    点击执行一次查看逻辑是否执行,控制台是否打印日志。

    注:若需要项目一致保持运行,选择启动即可。

    在这里插入图片描述

    运行结果

    控制台输出日志

    在这里插入图片描述

    以上就是Spring Boot集成XXL-JOB的具体详细过程,感谢阅读。

    参考资料

    [1] XXL-JOB分布式任务调度平台: https://www.xuxueli.com/xxl-job/

  • 相关阅读:
    路由守卫的参数to,from,next是什么?怎么用?
    java毕业设计驾考预约系统(附源码、数据库)
    JVM监控:JMX组件与底层原理
    怎样图片转文字?两分钟让你实现快速转文字
    极智Paper | 单级特征检测网络 YOLOF
    让iframe为项目增加更多可能性
    【校招VIP】前端算法考察之字符串
    如何看待铺天盖地都是Python的广告?
    EMT4J——让 Java 应用升级更轻松
    Oracle EBS Interface/API(50)-创建员工API
  • 原文地址:https://blog.csdn.net/weixin_43759352/article/details/134363475