xxl-Job详解(整合springboot)超详细
XXL-JOB简介
有兴趣的小伙伴可以去看一下他的官网:分布式任务调度平台XXL-JOB (xuxueli.com)
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=com.mysql.cj.jdbc.Driver
application.properties配置文件最上方可以指定访问端口
### web server.port=8888 server.servlet.context-path=/xxl-job-admin
application.properties配置文件最下方可以指定访问令牌(可以随意设置)
### xxl-job, access token xxl.job.accessToken=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配置文件中自行设置的) 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
打包项目
打开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依赖
com.xuxueli xxl-job-core 2.3.1
二、配置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、引入依赖: * * org.springframework.cloud * spring-cloud-commons * ${version} * * * 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服务跑通后), 为自己设置的执行器地址和默认端口)
如果不需要本地进行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.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
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构建文件中,确保以下类似的依赖:
mysql mysql-connector-java 最新版本
如果你手动下载了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.cnf或my.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 执行器就会注册两次导致执行器注册数量不对
解决思路:
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
解决办法:
将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.net/qq_57581439/article/details/128319069
- 源码编译(Windows/Linux)