XXL-JOB简介
有兴趣的小伙伴可以去看一下他的官网:分布式任务调度平台XXL-JOB (xuxueli.***)
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,查看一下目录
3、初始化数据库,配置数据库连接信息(在本地导入上图中的sql文件,并把配置文件给改好)
### 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=***.mysql.cj.jdbc.Driver
application.properties配置文件最上方可以指定访问端口
### web
server.port=8888
server.servlet.context-path=/xxl-job-admin
application.properties配置文件最下方可以指定访问令牌(可以随意设置)
### xxl-job, a***ess token
xxl.job.a***essToken=Lv2023
4.编译运行
访问http://localhost:8888(自己设置的端口)/xxl-job-admin/toLogin
进入管理页面。默认账号/密码:admin/123456
二、源码编译(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配置文件中自行设置的)
a***essToken: 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
a***essToken: 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
打包项目
打开jar包目录, 导入到服务器中
服务器端设置好jar存放目录并将jar包导入
启动命令
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
使用XXL-JOB(集成SpringBoot)
(必须两个服务都在本地,或者都在服务器端)
SpringBoot配置:
一、导入maven依赖
<!-- xxl-job-core -->
<dependency>
<groupId>***.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配置文件中自行设置的)
a***essToken: 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
a***essToken: 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 ***.Lv.job.config;
import ***.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.a***essToken}")
private String a***essToken;
@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.setA***essToken(a***essToken);
xxlJobSpringExecutor.setLogPath(logPath);
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
logger.info("\n>>>>>>>>>>> xxl-job config , adminAddresses = {} , appName = {}",adminAddresses,appName);
return xxlJobSpringExecutor;
}
/**
* 针对多网卡、容器内部署等情况,可借助 "spring-cloud-***mons" 提供的 "I***Utils" 组件灵活定制注册IP;
*
* 1、引入依赖:
* <dependency>
* <groupId>org.springframework.cloud</groupId>
* <artifactId>spring-cloud-***mons</artifactId>
* <version>${version}</version>
* </dependency>
*
* 2、配置文件,或者容器启动变量
* spring.cloud.i***utils.preferred-***works: 'xxx.xxx.xxx.'
*
* 3、获取IP
* String ip_ = i***Utils.findFirstNonLoopbackHostInfo().getIpAddress();
*/
}
四、Demo.java
package ***.Lv.job.business.Demo;
import ***.xxl.job.core.biz.model.ReturnT;
import ***.xxl.job.core.context.XxlJobHelper;
import ***.xxl.job.core.handler.annotation.XxlJob;
import io.swagger.annotations.ApiModel;
import org.springframework.stereotype.***ponent;
@ApiModel("测试报表任务")
@***ponent
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服务跑通后), 为自己设置的执行器地址和默认端口)
如果不需要本地进行job的测试, 可以编辑执行器 -> 注册方式改为手动录入(将服务器的机器地址保留)
二、配置任务管理(配合Demo.java看)Cron表达式放最后了
三、测试
执行后, 查看点击操作种的查询日志, 看日志信息, 是否执行成功,(如果没成功, 看报错信息进行更改)
四、查看运行结果
xxlJob执行日志
或者看控制台中的日志
springboot中Job模块执行日志
五、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.CannotGetJdb***onnectionException: 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 ***.xxl.job.admin.dao.XxlJobUserDao.loadByUserName
### The error o***urred while executing a query
### Cause: org.springframework.jdbc.CannotGetJdb***onnectionException: Failed to obtain JDBC Connection; nested exception is java.sql.SQLNonTransientConnectionException: Could not create connection to database server. Attempted reconnect 3 times. Giving up
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.***f或my.ini文件。这个文件通常位于MySQL的安装目录下,也可能位于**/etc/目录下或/etc/mysql/或/etc/my.***f.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 执行器就会注册两次导致执行器注册数量不对
解决思路:
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.setA***essToken(a***essToken);
xxlJobSpringExecutor.setLogPath(logPath);
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
logger.info("\n>>>>>>>>>>> xxl-job config , adminAddresses = {} , appName = {}",adminAddresses,appName);
return xxlJobSpringExecutor;
}
详细的可以看下方文章:
https://blog.csdn.***/qq_42651904/article/details/120555995?spm=1001.2014.3001.5506
执行器报错相关问题
xxl-job remoting error(connect timed out), for url : http://xxxx:端口/run
解决办法:
将xxlJob应用和jar包服务所在的机器开启xxl_job访问地址端口和执行器默认端口9999的安全组和防火墙端口 (我的访问端口是8888)
xxl-job remoting error(拒绝连接 (Connection refused), for url : http://xxxx:端口/run
解决办法:
如果xxl-job执行器自动注册有机器, 还是被拒绝连接(可能是执行器机器所在的问题)
查看两台服务器
1.xxl-job所在机器 和 jar包程序所在机器的9999端口是否被监听
发现xxl-job应用所在的机器, 没有监听执行器的9999端口, 导致连接不上, 一直被拒绝.
需要我们在jar包的配置中更改xxl-job的执行器机器为能被监听的那台机器的ip
执行器ip更改为监听9999端口的机器ip, 重新发布,启动jar包即可解决
部分文章内容引自
https://blog.csdn.***/qq_57581439/article/details/128319069