XXL-JOB+架构设计
本文最后更新于 2025-03-24,文章超过7天没更新,应该是已完结了~
环境配置
拉取镜像
docker pull xuxueli/xxl-job-admin:2.3.1
创建目录和配置文件
创建目录 /data/soft/xxl-job/applogs
在/data/soft/xxl-job/application.properties创建配置文件。这种方式是springboot外部加载配置其中一种方式
### web
server.port=8080
server.servlet.context-path=/xxl-job-admin
### actuator
management.server.servlet.context-path=/actuator
management.health.mail.enabled=false
### resources
spring.mvc.servlet.load-on-startup=0
spring.mvc.static-path-pattern=/static/**
spring.resources.static-locations=classpath:/static/
### freemarker
spring.freemarker.templateLoaderPath=classpath:/templates/
spring.freemarker.suffix=.ftl
spring.freemarker.charset=UTF-8
spring.freemarker.request-context-attribute=request
spring.freemarker.settings.number_format=0.##########
### mybatis
mybatis.mapper-locations=classpath:/mybatis-mapper/*Mapper.xml
#mybatis.type-aliases-package=com.xxl.job.admin.core.model
### xxl-job, datasource
spring.datasource.url=jdbc:mysql://192.168.101.68:3306/xxl_job_2.3.1?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=mysql
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
### datasource-pool
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.hikari.minimum-idle=10
spring.datasource.hikari.maximum-pool-size=30
spring.datasource.hikari.auto-commit=true
spring.datasource.hikari.idle-timeout=30000
spring.datasource.hikari.pool-name=HikariCP
spring.datasource.hikari.max-lifetime=900000
spring.datasource.hikari.connection-timeout=10000
spring.datasource.hikari.connection-test-query=SELECT 1
spring.datasource.hikari.validation-timeout=1000
### xxl-job, email
spring.mail.host=smtp.qq.com
spring.mail.port=25
spring.mail.username=xxx@qq.com
spring.mail.from=xxx@qq.com
spring.mail.password=xxx
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
### xxl-job, access token
xxl.job.accessToken=default_token
### xxl-job, i18n (default is zh_CN, and you can choose "zh_CN", "zh_TC" and "en")
xxl.job.i18n=zh_CN
## xxl-job, triggerpool max size
xxl.job.triggerpool.fast.max=200
xxl.job.triggerpool.slow.max=100
### xxl-job, log retention days
xxl.job.logretentiondays=30
创建数据库:xxl_job_2.3.1
导入xxl_job_2.3.1.sql,如下:
创建容器
docker run -d -e \
--restart=always \
-v /data/soft/xxl-job/applogs:/data/applogs \ --->容器内/data/applog这个路径的数据挂载在宿主机/data/soft/xxl-job/applogs,放日志用
-v /data/soft/xxl-job/application.properties:/application.properties \ --->这个放配置文件用
-p 8088:8080 \
--name xxl-job-admin \
xuxueli/xxl-job-admin:2.3.1
启动成功进入管理界面:
http://192.168.101.68:8088/xxl-job-admin
账号/密码:admin/123456
3.2.1 搭建XXL-JOB环境
目标:搭建xxl-job环境
1)分布式调度平台XXL-JOB介绍
对于开通区域列表的缓存数据需要由定时任务每天凌晨更新缓存,如何实现定时任务呢?
1、使用jdk提供的Timer定时器
示例代码如下:
每个Timer对应一个线程,可以同时启动多个Timer定时执行多个任务。
public static void main(String[] args){
Timer timer = new Timer();
timer.schedule(new TimerTask(){
@Override
public void run() {
//TODO:something
}
}, 1000, 2000); //1秒后开始调度,每2秒执行一次
}
Time使用简单,可以实现每隔一定的时间去执行任务,但无法实现每天凌晨去执行任务,即在某个时间点去执行任务。
2、使用第三方Quartz方式实现
Quartz 是一个功能强大的任务调度框架(项目地址:https://github.com/quartz-scheduler/quartz ),它可以满足更多更复杂的调度需求,Quartz 设计的核心类包括 Scheduler, Job 以及 Trigger。其中,Job 负责定义需要执行的任务,Trigger 负责设置调度策略,Scheduler 将二者组装在一起,并触发任务开始执行。Quartz支持简单的按时间间隔调度、还支持按日历调度方式,通过设置CronTrigger表达式(包括:秒、分、时、日、月、周、年)进行任务调度。
虽然Quartz可以实现按日历调度的方式,但无法支持分布式环境下任务调度。分布式环境下通常一个服务部署多个实例即多个jvm进程,假设运营基础服务部署两个实例每个实例定时执行更新缓存的任务,两个实例就会重复执行。如下图:
暂时无法在飞书文档外展示此内容
3、使用分布式调度平台XXL-JOB
在分布式环境下进行任务调度需要使用分布式任务调度平台,XXL-JOB是一个轻量级分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。
官网:https://www.xuxueli.com/xxl-job/
文档:https://www.xuxueli.com/xxl-job/#%E3%80%8A%E5%88%86%E5%B8%83%E5%BC%8F%E4%BB%BB%E5%8A%A1%E8%B0%83%E5%BA%A6%E5%B9%B3%E5%8F%B0XXL-JOB%E3%80%8B
XXL-JOB主要有调度中心、执行器、任务:
调度中心(网页可视化操作设置执行器及其绑定的任务):
负责管理调度信息,按照调度配置发出调度请求,自身不承担业务代码;
主要职责为执行器管理、任务管理、监控运维、日志管理等
任务执行器(编码设置执行的具体任务):
负责接收调度请求并执行任务逻辑;
主要职责是执行任务、执行结果上报、日志服务等
使用XXL-JOB就可以解决使用多个jvm进程重复执行任务的问题,如下图:
XXL-JOB调度中心可以配置路由策略,比如:第一个、轮询策略、分片等,它们分别表示的意义如下:
第一个:即每次执行任务都由第一个执行器去执行。
轮询:即执行器轮番执行。
分片:每次执行任务广播给每个执行器让他们同时执行任务。
如果根据需求每次执行任务仅由一个执行器去执行任务可以设置路由策略:第一个、轮询。
如果根据需求每次执行任务由多个执行器同时执行可以设置路由策略为:分片。
2.启动xxl-job
执行docker start xxl-job-admin 启动xxl-job
访问:http://192.168.101.68:8088/xxl-job-admin/
账号和密码:admin/123456
3) 执行器
1.添加执行器依赖
下边配置执行器,执行器负责与调度中心通信接收调度中心发起的任务调度请求,执行器负责执行微服务中定义的任务,执行器程序由xxl-job提供,在微服务中引入下边的依赖即加入了执行器的程序:
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
</dependency>
本项目在framework中定义了jzo2o-xxl-job工程,它对执行器bean执行了定义:
目的是为了配置 XXL-Job 执行器(XxlJobSpringExecutor),并将它作为 Spring Boot 应用中的一个 Bean 注册到容器中,从而让 XXL-Job 调度中心可以调用这个执行器执行任务
@Slf4j
@Configuration
@ConditionalOnProperty(prefix = "xxl-job", value = "enable", havingValue = "true") //只有当配置文件中属性 xxl-job.enable 的值为 "true" 时,才会激活这个配置类
@EnableConfigurationProperties(XxlJobProperties.class)
public class XxlJobConfiguration {
@Bean
public XxlJobSpringExecutor xxlJobExecutor(XxlJobProperties prop) {
log.info(">>>>>>>>>>> xxl-job config init.");
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
XxlJobProperties.Admin admin = prop.getAdmin();
if (admin != null && StringUtils.isNotEmpty(admin.getAddress())) {
xxlJobSpringExecutor.setAdminAddresses(admin.getAddress());
}
XxlJobProperties.Executor executor = prop.getExecutor();
xxlJobSpringExecutor.setAccessToken(prop.getAccessToken());
if (executor != null) {
xxlJobSpringExecutor.setIp(executor.getIp());
xxlJobSpringExecutor.setAppname(executor.getAppName());
xxlJobSpringExecutor.setPort(executor.getPort());
xxlJobSpringExecutor.setLogPath(executor.getLogPath());
xxlJobSpringExecutor.setLogRetentionDays(
executor.getLogRetentionDays()
);
}
log.info(">>>>>>>>>>> xxl-job config end.");
return xxlJobSpringExecutor;
}
}
@Data
@ConfigurationProperties(prefix = "xxl-job")
@Configuration
public class XxlJobProperties {
private String accessToken;
private Admin admin;
private Executor executor;
@Data
public static class Admin {
private String address;
}
@Data
public static class Executor {
private String appName;
private String ip;
private Integer port;
private String logPath;
private Integer logRetentionDays;
}
}
为什么要配置这段代码?
连接调度中心
执行器需要知道调度中心的地址和认证信息,才能正确接收并执行调度中心下发的任务。通过配置 admin 地址、访问令牌等信息,执行器能够与调度中心进行通信。
所以在需要使用xxl-job的微服务中需要引入下边的依赖,在jzo2o-foundations服务中引入下边的依赖:
<dependency>
<groupId>com.jzo2o</groupId>
<artifactId>jzo2o-xxl-job</artifactId>
</dependency>
2.配置xxl-job
接下来进入nacos,配置shared-xxl-job.yaml:
说明:
address:调度中心的地址
appName:执行器名称,为spring.application.name表示微服务的名称(在bootstrap.yml中配置)
port:执行器端口号,通过xxl-job.port配置
在jzo2o-foundations.yaml中配置执行器的端口:
在jzo2o-foundations中加载shared-xxl-job.yaml:
3. 下边进入调度中心添加执行器
进入调度中心,进入执行器管理界面,如下图:
点击新增,填写执行器信息
AppName:执行名称,在shared-xxl-job.yaml中指定执行器名称就是微服务的应用名。
名称:取一个中文名称。
注册方式:自动注册,只要执行器和调度中心连通执行器会自动注册到调度中心
机器地址:自动注册时不用填写。
找到应用名:jzo2o-foundations,如下图:
添加成功:
启动jzo2o-foundations,查看jzo2o-foundations的控制台:
>>>>>>>>>>> xxl-job remoting server start success, nettype = class com.xxl.job.core.server.EmbedServer, port = 11603 说明执行器启动成功。
稍等片刻进入 xxl-job调度中心,进入执行器管理界面,执行器注册成功:
点击“查看(1)”,查看执行器的地址,如下图:
3.2.2 定义缓存更新任务
根据本节的目标,使用xxl-job定时更新开通区域列表的缓存。
1)编写任务方法
定时执行任务就需要编写任务方法,此任务方法由执行器去调用。
可以参考xxl-job源码去编写任务方法,从源码目录中找到执行器示例代码:
xxl-job-2.3.1\xxl-job-executor-samples\xxl-job-executor-sample-springboot\src\main\java\com\xxl\job\executor\service\jobhandler\SampleXxlJob.java
部分示例代码如下,下边代码中demoJobHandler()就是一个任务方法,需要使用@XxlJob注解标识,所在类需要由spring去管理,所以加了@Component注解。
@Component
public class SampleXxlJob {
private static Logger logger = LoggerFactory.getLogger(SampleXxlJob.class);
/**
* 1、简单任务示例(Bean模式)
*/
@XxlJob("demoJobHandler")
public void demoJobHandler() throws Exception {
XxlJobHelper.log("XXL-JOB, Hello World.");
for (int i = 0; i < 5; i++) {
XxlJobHelper.log("beat at:" + i);
TimeUnit.SECONDS.sleep(2);
}
// default success
}
....
参考上边的代码我们编写更新开通区域列表缓存的任务方法:
先删除开通区域的缓存,再查询开通区域列表进行缓存。
package com.jzo2o.foundations.handler;
import com.jzo2o.foundations.constants.RedisConstants;
import com.jzo2o.foundations.service.IRegionService;
import com.jzo2o.foundations.service.IServeService;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* springCache缓存同步任务
*
* @author itcast
* @create 2023/8/15 18:14
**/
@Slf4j
@Component
public class SpringCacheSyncHandler {
@Resource
private IRegionService regionService;
@Resource
private RedisTemplate redisTemplate;
/**
* 已启用区域缓存更新
* 每日凌晨1点执行
*/
@XxlJob(value = "activeRegionCacheSync")
public void activeRegionCacheSync() {
log.info(">>>>>>>>开始进行缓存同步,更新已启用区域");
//1.清理缓存
String key = RedisConstants.CacheName.JZ_CACHE + "::ACTIVE_REGIONS";
redisTemplate.delete(key);
//2.刷新缓存
regionService.queryActiveRegionListCache();
log.info(">>>>>>>>更新已启用区域完成");
}
}
2)配置任务
下边在调度中心配置任务。
进入任务管理,新增任务:
填写任务信息:
说明:
调度类型:
固定速度指按固定的间隔定时调度。
Cron,通过Cron表达式实现更丰富的定时调度策略。
Cron表达式是一个字符串,通过它可以定义调度策略,格式如下:
{秒数} {分钟} {小时} {日期} {月份} {星期} {年份(可为空)}
xxl-job提供图形界面去配置:
一些例子如下:
0 0 0 * * ? 每天0点触发
30 10 1 * * ? 每天1点10分30秒触发
0/30 * * * * ? 每30秒触发一次
* 0/10 * * * ? 每10分钟触发一次
为了方便测试这里第5秒执行一次,设置为:0/5 * * * * ?
运行模式有BEAN和GLUE,bean模式较常用就是在项目工程中编写执行器的任务代码,GLUE是将任务代码编写在调度中心。
JobHandler即任务方法名,填写任务方法上边@XxlJob注解中的名称。
路由策略:
第一个:即每次执行任务都由第一个执行器去执行。
轮询:即执行器轮番执行。
分片:每次执行任务广播给每个执行器让他们同时执行任务。
详细说明xxl-job源码中的doc目录下的文档:
3)启动任务并测试
任务配置完成,下边启动任务
启动成功:
我们在任务方法上打断点跟踪,任务方法被执行,如下图:
尝试启用或禁用一个区域,观察redis中开通区域列表缓存是否更新。
- 感谢你赐予我前进的力量