XXL-JOB简介

有兴趣的小伙伴可以去看一下他的官网:分布式任务调度平台XXL-JOB (xuxueli.com)

image.png

XXL-JOB是什么

解释

XXL-JOB是一个分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。
为什么要叫 XXL 呢?答:是因为他的作者的名字叫许雪里,使用了名字的缩写
分布式任务调度平台是什么呢?答:一个定时任务实现方案

在平时的业务场景中,经常有一些场景需要使用定时任务,比如:

时间驱动的场景:某个时间点发送优惠券,发送短信等等。
批量处理数据:批量统计上个月的账单,统计上个月销售数据等等。
固定频率的场景:每隔5分钟需要执行一次。
所以定时任务在平时开发中并不少见,而且对于现在快速消费的时代,每天都需要发送各种推送,消息都需要依赖定时任务去完成.


为什么需要任务调度平台,而不用传统的 Timer 与 Quartz

在Java中,传统的定时任务实现方案,比如Timer,Quartz等都或多或少存在一些问题:

  • 不支持集群、不支持统计、没有管理平台、没有失败报警、没有监控等等而且在现在分布式的架构中,有一些场景需要分布式任务调度:
  • 同一个服务多个实例的任务存在互斥时,需要统一的调度。
  • 任务调度需要支持高可用、监控、故障告警。
  • 需要统一管理和追踪各个服务节点任务调度的结果,需要记录保存任务属性信息等。

显然传统的定时任务已经不满足现在的分布式架构,所以需要一个分布式任务调度平台,目前比较主流的是elasticjob和xxl-job。

为什么选择XXL-JOB,不选择elasticjob

跟xxl-job不同的是,elasticjob是采用zookeeper实现分布式协调,实现任务高可用以及分片。

  • xxl-job环境依赖于mysql,elasticjob依赖于ZooKeeper,这也是最大的不同。
  • elasticjob是无中心化的,通过ZooKeeper的选举机制选举出主服务器,如果主服务器挂了,会重新选举新的主服务器。因此elasticjob具有良好的扩展性和可用性,但是使用和运维有一定的复杂.
  • xxl-job则相反,是通过一个中心式的调度平台,调度多个执行器执行任务,调度中心通过DB锁保证集群分布式调度的一致性,这样扩展执行器会增大DB的压力,但是如果实际上这里数据库只是负责任务的调度执行。但是如果没有大量的执行器的话和任务的情况,是不会造成数据库压力的。实际上大部分公司任务数,执行器并不多(虽然面试经常会问一些高并发的问题)。

相对来说,xxl-job中心式的调度平台轻量级,开箱即用,操作简易,上手快,与SpringBoot有非常好的集成,而且监控界面就集成在调度中心,界面又简洁,对于企业维护起来成本不高,还有失败的邮件告警等等。这就使很多企业选择xxl-job做调度平台。

学习之前必看,少走很多弯路

我先讲一下xxl-job的运行原理(我自己的理解):
xxl-job是一个网页,用来处理注册在里面的请求,并每过多长的时间(自己设置)就会传递一个值给springboot,这样就会出现一个问题:xxl-job要在局域网下才能连接成功。

就会出现本地的服务(springboot)是连接不上服务器端(xxl-job)的

为什么?
在同一个网段下(本地),xxl-job可以给本地服务(springboot)发送服务;但如果xxl-job是在服务器上,那么你能跟他通信,但他不能给你通信,意思就是他ping你的ip是ping不通的

解决方法1:
先在本地做测试的环境(xxlJob和springboot服务都在本地),服务器上的也做一样的配置,本地把服务(springboot)打包后,上传服务器,那么两个服务器直接就可以建立联系,或者上传到同一服务器上,组成服务器的本地环境
解决方法2:
进入服务器上的xxl-job访问不了本地的,是因为本地不能被外网访问,那么就用内网穿透工具,让外网服务器可以访问本地端口就行


安装XXL-JOB

  • 源码编译(Windows/Linux)

一、源码编译(Windows)

1、拉取源码:xxl-job: 一个分布式任务调度平台
2、导入IDEA,查看一下目录

image.png

3、初始化数据库,配置数据库连接信息(在本地导入上图中的sql文件,并把配置文件给改好)

image.png

image.png

### xxl-job, datasource
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

application.properties配置文件最上方可以指定访问端口
image.png

### web
server.port=8888
server.servlet.context-path=/xxl-job-admin

application.properties配置文件最下方可以指定访问令牌(可以随意设置)
image.png

### xxl-job, access token
xxl.job.accessToken=Lv2023
4.编译运行

访问http://localhost:8888(自己设置的端口)/xxl-job-admin/toLogin
进入管理页面。默认账号/密码:admin/123456

image.png

二、源码编译(Linux)

将配置好xxlJob连接信息的springBoot项目配置好mysql连接信息的xxlJob项目, 打包成jar包
(我的springBoot项目是使用jenkins进行打包发布的, 详情可以看这篇文章
jenkins的安装与配置(超详细)
springBoot项目配置xxlJob连接信息(我用的是开发和测试环境, 并且将配置信息放在job模块中)

springBoot项目配置xxlJob连接信息

SpringBoot配置详情可以看(本文章下方SpringBoot配置内容)

#开发dev环境
xxl:
  job:
    admin:
        #xxlJob访问地址
      addresses: http://ip地址:8888(访问端口)/xxl-job-admin
    #xxlJob访问令牌(在xxlJob配置文件中自行设置的)
    accessToken: Lv2023
    executor:
      appname: ${JOB_EXECUTOR_APP_NAME:xxl-job-executor-sample}
    	#xxlJob执行器地址
      ip: ${JOB_EXECUTOR_IP:127.0.0.1}
      port: 0
      # 日志地址
      logpath: /home/workspace/xxl-job/jobhandler
      # 日志保存时间
      logretentiondays: 30

#测试test环境
xxl:
  job:
    admin:
      addresses: http://ip地址:8888(访问端口)/xxl-job-admin
    accessToken: Lv2023
    executor:
      appname: ${JOB_EXECUTOR_APP_NAME:xxl-job-executor-sample}
      ip: ${JOB_EXECUTOR_IP:(执行器ip地址}
      port: 0
      logpath: /home/workspace/xxl-job/jobhandler
      logretentiondays: 30
打包项目

image.png

打开jar包目录, 导入到服务器中

image.png
服务器端设置好jar存放目录并将jar包导入
image.png

启动命令

nohup java -jar xxl-job-admin-2.4.1-SNAPSHOT.jar >xxlJobLog.txt &
解释: (后台运行 xxl-job-admin-2.4.1-SNAPSHOT.jar 这个jar包, 并在运行后生成xxlJobLog.txt日志文件)

访问服务端xxlJob页面

(服务器别忘开放安全组和防火墙端口)
访问http://服务端xxlJob地址或域名:8888(自行设置的访问端口)/xxl-job-admin/toLogin
默认账号/密码:admin/12345
image.png


使用XXL-JOB(集成SpringBoot)

(必须两个服务都在本地,或者都在服务器端)

SpringBoot配置:

一、导入maven依赖
        <!-- xxl-job-core -->
        <dependency>
            <groupId>com.xuxueli</groupId>
            <artifactId>xxl-job-core</artifactId>
            <version>2.3.1</version>
        </dependency>

二、配置yam
#开发dev环境
xxl:
  job:
    admin:
        #xxlJob访问地址
      addresses: http://ip地址:8888(访问端口)/xxl-job-admin
    #xxlJob访问令牌(在xxlJob配置文件中自行设置的)
    accessToken: Lv2023
    executor:
    	#执行器名称
      appname: ${JOB_EXECUTOR_APP_NAME:xxl-job-executor-sample}
    	#xxlJob执行器地址
      ip: ${JOB_EXECUTOR_IP:127.0.0.1}
      port: 0
      # 日志地址
      logpath: /home/workspace/xxl-job/jobhandler
      # 日志保存时间
      logretentiondays: 30

#测试test环境
xxl:
  job:
    admin:
      addresses: http://ip地址:8888(访问端口)/xxl-job-admin
    accessToken: Lv2023
    executor:
      appname: ${JOB_EXECUTOR_APP_NAME:xxl-job-executor-sample}
      ip: ${JOB_EXECUTOR_IP:(执行器ip地址}
      port: 0
      logpath: /home/workspace/xxl-job/jobhandler
      logretentiondays: 30
三、XxlJobConfig配置类
package com.Lv.job.config;

import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
@Slf4j
public class XxlJobConfig {
    private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);

    @Value("${xxl.job.admin.addresses}")
    private String adminAddresses;

    @Value("${xxl.job.executor.appname}")
    private String appName;

    @Value("${xxl.job.executor.ip}")
    private String ip;

    @Value("${xxl.job.executor.port}")
    private int port;

    @Value("${xxl.job.accessToken}")
    private String accessToken;

    @Value("${xxl.job.executor.logpath}")
    private String logPath;

    @Value("${xxl.job.executor.logretentiondays}")
    private int logRetentionDays;


    @Bean
    public XxlJobSpringExecutor xxlJobExecutor() {
        log.info("\n>>>>>>>>>>> xxl-job config init.");
        XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
        xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
        xxlJobSpringExecutor.setAppname(appName);
        xxlJobSpringExecutor.setIp(ip);
        xxlJobSpringExecutor.setPort(port);
        xxlJobSpringExecutor.setAccessToken(accessToken);
        xxlJobSpringExecutor.setLogPath(logPath);
        xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
        logger.info("\n>>>>>>>>>>> xxl-job config , adminAddresses = {} , appName = {}",adminAddresses,appName);
        return xxlJobSpringExecutor;
    }

    /**
     * 针对多网卡、容器内部署等情况,可借助 "spring-cloud-commons" 提供的 "InetUtils" 组件灵活定制注册IP;
     *
     *      1、引入依赖:
     *          <dependency>
     *             <groupId>org.springframework.cloud</groupId>
     *             <artifactId>spring-cloud-commons</artifactId>
     *             <version>${version}</version>
     *         </dependency>
     *
     *      2、配置文件,或者容器启动变量
     *          spring.cloud.inetutils.preferred-networks: 'xxx.xxx.xxx.'
     *
     *      3、获取IP
     *          String ip_ = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress();
     */


}

四、Demo.java
package com.Lv.job.business.Demo;

import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import io.swagger.annotations.ApiModel;
import org.springframework.stereotype.Component;


@ApiModel("测试报表任务")
@Component
public class XxlDemoHandler {

    @XxlJob("DemoHandler")
    public void demo() throws Exception {
        XxlJobHelper.log("测试开始");
        String param = XxlJobHelper.getJobParam();
        System.out.println();
        System.out.println();
        System.out.println();
        System.out.println(param);
        System.out.println("测试完成!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
        System.out.println();
        System.out.println();
        System.out.println();
        XxlJobHelper.log("测试开结束");
    }
}

XXL-JOB配置(与上文的yaml文件结合着看)

一、配置执行器

本地服务跑通后, 自动获取为127.0.0.1:9999(xxlJob默认执行器端口号)
服务端(springBoot服务跑通后), 为自己设置的执行器地址和默认端口)
image.png

如果不需要本地进行job的测试, 可以编辑执行器 -> 注册方式改为手动录入(将服务器的机器地址保留)
image.png
image.png

二、配置任务管理(配合Demo.java看)Cron表达式放最后了

image.png

三、测试

image.png
执行后, 查看点击操作种的查询日志, 看日志信息, 是否执行成功,(如果没成功, 看报错信息进行更改)
image.png

四、查看运行结果

xxlJob执行日志
image.png
或者看控制台中的日志
image.png
image.png

springboot中Job模块执行日志
image.png

五、Cron生成器

(一般不需要自己写, 了解下即可)
在线Cron表达式生成器

Cron学习:

Cron表达式简单学习


遇到的问题

XXLJOB登陆提示Attempted reconnect 3 times. Giving up

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is java.sql.SQLNonTransientConnectionException: Could not create connection to database server. Attempted reconnect 3 times. Giving up.
### The error may exist in class path resource [mybatis-mapper/XxlJobUserMapper.xml]
### The error may involve com.xxl.job.admin.dao.XxlJobUserDao.loadByUserName
### The error occurred while executing a query
### Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is java.sql.SQLNonTransientConnectionException: Could not create connection to database server. Attempted reconnect 3 times. Giving up

image.png

SSL握手的问题

解决办法;

看了XXLJOB的启动日志发现, 是数据库连接时出现了SSL握手的问题,数据库连接使用了SSL,但握手失败引起的

检查数据库连接参数:

确保数据库连接参数正确。在你的配置中,spring.datasource.url中的连接字符串包含了SSL相关的配置。如果数据库并没有启用SSL,可以尝试将连接字符串修改为不使用SSL的版本。例如:

spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai&useSSL=false

这会将useSSL参数设置为false

检查数据库SSL配置:

如果数据库确实使用SSL,确保数据库端的SSL配置正确。可能需要检查数据库配置文件,确保SSL证书和密钥的路径正确,并且数据库已正确配置为接受SSL连接。

检查JDBC驱动版本:

确保使用的MySQL JDBC驱动是最新的版本。你可以访问MySQL官方网站或者Maven中央仓库获取最新版本的MySQL驱动。在你的pom.xml或者Gradle构建文件中,确保以下类似的依赖:

<!-- For Maven -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>最新版本</version>
</dependency>

如果你手动下载了JDBC驱动的JAR文件,确保它是最新版本。

排除SSL问题:

为了快速解决问题,你可以尝试在连接字符串中排除SSL,以验证问题是否与SSL握手有关。在spring.datasource.url中添加以下参数:

spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true

useSSL=false禁用SSL,allowPublicKeyRetrieval=true允许获取公钥。

检查网络和防火墙:

确保服务器之间的网络连接正常,并且防火墙没有阻止数据库连接。
尝试上述建议,并根据实际情况调整配置,以解决SSL握手问题。


数据库配置SSL

在MySQL服务器上,通过以下方法检查是否启用了SSL配置:

查看MySQL配置文件:

打开MySQL的配置文件,通常是my.cnfmy.ini文件。这个文件通常位于MySQL的安装目录下,也可能位于**/etc/目录下或/etc/mysql//etc/my.cnf.d/**目录中,。使用文本编辑器查看该文件,查找是否存在以下配置项:

[mysqld]
ssl-key=/path/to/server-key.pem
ssl-cert=/path/to/server-cert.pem
ssl-ca=/path/to/ca-cert.pem

如果存在类似上述配置项,说明MySQL服务器启用了SSL。

使用MySQL客户端检查:

使用MySQL客户端连接到数据库,并执行以下SQL语句:

SHOW VARIABLES LIKE 'have_ssl';

如果结果中的Value列显示YES,则表示MySQL服务器启用了SSL。

查看错误日志:

MySQL的错误日志文件通常包含有关SSL配置的信息。在MySQL的配置文件中,你可以查找log-error参数指定的错误日志文件的位置。查看该文件,检查是否有SSL相关的信息,以及是否存在任何与SSL握手或证书相关的错误。

通过命令行参数启动MySQL:

如果MySQL服务器是通过命令行参数启动的,你可以检查启动命令中是否包含SSL相关的选项。例如:

mysqld --ssl-key=/path/to/server-key.pem --ssl-cert=/path/to/server-cert.pem --ssl-ca=/path/to/ca-cert.pem

如果命令中包含以上SSL相关的选项,说明MySQL服务器启用了SSL。

查看MySQL状态信息:

使用MySQL客户端连接到数据库,并执行以下SQL语句:

SHOW STATUS LIKE 'Ssl_cipher';

如果结果非空,表示SSL已经启用,并且显示了使用的SSL密码套件。


执行器Online机器地址(注册节点)加倍问题

发现服务启动后, 执行器机器地址变成了双倍, 相同ip地址, 但是端口号一个9999,一个10000
原因:
XxlJobSpringExecutor本身是实现了SmartInitializingSingleton接口,
afterSingletonsInstantiated方法本身就调用了父类(XxlJobExecutor)的start方法,
如果再执行initMethod指定的start,就会导致调用两次start方法(初始化bean一次,bean初始化完又调用一次),xxl 执行器就会注册两次导致执行器注册数量不对

image.png
解决思路:
Bean之前是这样的,多添加了一个initMethod,去掉即可
@Bean(initMethod = "start", destroyMethod = "destroy")

 @Bean
    public XxlJobSpringExecutor xxlJobExecutor() {
        log.info("\n>>>>>>>>>>> xxl-job config init.");
        XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
        xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
        xxlJobSpringExecutor.setAppname(appName);
        xxlJobSpringExecutor.setIp(ip);
        xxlJobSpringExecutor.setPort(port);
        xxlJobSpringExecutor.setAccessToken(accessToken);
        xxlJobSpringExecutor.setLogPath(logPath);
        xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
        logger.info("\n>>>>>>>>>>> xxl-job config , adminAddresses = {} , appName = {}",adminAddresses,appName);
        return xxlJobSpringExecutor;
    }

详细的可以看下方文章:
https://blog.csdn.net/qq_42651904/article/details/120555995?spm=1001.2014.3001.5506

执行器报错相关问题

xxl-job remoting error(connect timed out), for url : http://xxxx:端口/run

image.png
解决办法:
将xxlJob应用和jar包服务所在的机器开启xxl_job访问地址端口和执行器默认端口9999的安全组和防火墙端口 (我的访问端口是8888)
image.png

xxl-job remoting error(拒绝连接 (Connection refused), for url : http://xxxx:端口/run

image.png
解决办法:
如果xxl-job执行器自动注册有机器, 还是被拒绝连接(可能是执行器机器所在的问题)
查看两台服务器
1.xxl-job所在机器 和 jar包程序所在机器的9999端口是否被监听
image.png
发现xxl-job应用所在的机器, 没有监听执行器的9999端口, 导致连接不上, 一直被拒绝.
需要我们在jar包的配置中更改xxl-job的执行器机器为能被监听的那台机器的ip
image.png
执行器ip更改为监听9999端口的机器ip, 重新发布,启动jar包即可解决

部分文章内容引自
https://blog.csdn.net/qq_57581439/article/details/128319069

GitHub 加速计划 / xx / xxl-job
27.15 K
10.79 K
下载
xxl-job: 是一个分布式任务调度平台,核心设计目标是开发迅速、学习简单、轻量级、易扩展。
最近提交(Master分支:2 个月前 )
e5d26ba2 - 3 个月前
977ad87b - 3 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐