XXL-Job

基础

简介

XXL-JOB 
	是一个分布式任务调度平台,核心设计目标是开发迅速、学习简单、轻量级、易扩展;
	
@XxlJob 以声明的形式定义和管理任务,无需编写复杂的调度逻辑,简化了定时任务和分布式任务的开发过程;

当前使用情况:
	1 cache缓存内容更新:为提高数据读取速率,将数据库中一些必要信息放入本地缓存中,但是更新数据库时,缓存中的信息不会更新,故此采用xxljob进行任务执行,更新cache内容;
	

参考:https://www.xuxueli.com/xxl-job/#3.3%20GLUE%E6%A8%A1%E5%BC%8F

使用要点

springboot项目要想使用xxl-job分布式任务调度平台,需要执行的配置信息如下:
1. springboot的配置文件 xml 或者 properties 文件;
2. xxljob执行器配置类编写
3. xxljob页面端配置
配置文件yml/properties
xxl.job: 
# 分布式任务调度平台,包含一个调度中心以及多个执行器节点;
  admin.addresses: 
  # 配置调度中心的地址列表,格式一般为http://ip:port
  executor:
  # 配置关于执行器节点的设置
    appname: qh-opn-api
    # 执行器的名称,用于在调度中心显示和识别
    ip:
    # 执行器所在的机器IP地址
    # 默认为空表示自动获取IP,多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯实用;
    # 地址信息用于 "执行器注册" 和 "调度中心请求并触发任务";
    port: 9992
    # 执行器监听的任务调度端口,单机部署多个执行器时,注意要配置不同执行器端口;
    logpath: /data/xxx/xxl-job/jobhandler
    # 任务执行日志的保存路径
    logretentiondays: 3
    # 日志文件保留天数,超过这个期限的日志文件会被清理
  accessToken: cde0ca3b87144737857c18b092f7f9a4
  # 安全令牌,用于身份验证,确保调度中心和执行器之间的通信安全,是一个密钥。
调度中心和执行器:
	调用中心是用来控制定时任务的触发逻辑,而执行器是具体执行任务的,这是一种任务和触发逻辑分离的设计思想。
	
xxl-job配置类
@Configuration
// 配置类
@Slf4j
// 提供对应的logger对象,用于日志输出
public class XxlJobConfig {

    @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.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;

	// 将配置文件(yml/properties)中的参数注入到该类中

    @Bean
    // 返回一个XxlJobSpringExecutor对象,Spring容器管理这个bean
    public XxlJobSpringExecutor xxlJobExecutor() {
        log.info("xxl-job config init.");
        XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
        xxlJobSpringExecutor.setLogPath(logPath);
        xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
        xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
        xxlJobSpringExecutor.setAppname(appname);
        xxlJobSpringExecutor.setIp(ip);
        xxlJobSpringExecutor.setPort(port);
        xxlJobSpringExecutor.setAccessToken(accessToken);
        return xxlJobSpringExecutor;
    }
}

XxlJobSpringExecutor 类理解:
在这里插入图片描述

项目使用1XxlJobConfig类,被集成到某个包里面了,将常用的配置类都集成到一个包中了,即在com.xxx.xx.common.xxl.config;

xxl-job 执行器任务编写
@Slf4j
// 提供对应的logger对象,用于日志输出
@Component
// 修饰类,标注该类为spring管理的bean
public class AXXXDispather {

    @Autowired
    // 让spring完成bean的自动装配
    AXXXCache axxxCache;
    // 本地缓存

    @ServiceId()
    // 自定义业务标签,标识当前是什么业务
    @XxlJob(XXJOB_xxx)
    // 用于标识某个方法作为定时任务的执行入口,参数表示任务的名称;
    public ReturnT<String> axxxCacheJobHandler(String param) {
            XxlJobLogger.log("[NODE ID] : {} , XXL-JOB, [axxx CACHE] -> START request body : {}", IdWorker.getWorkerId(),param);
            // xxljob日志记录
            log.info("[NODE ID] : {} , XXL-JOB, [axxx CACHE] -> START request body : {}",IdWorker.getWorkerId(),param);
            // logger对象日志记录
            String lock = IdWorker.getWorkerId() +
                    SystemConsts.LINE + this.getClass().getName() +
                    SystemConsts.LINE + "axxxJobHandler";
            log.info("[NODE ID] : {} , XXL-JOB, [axxx CACHE]  lock : {}", IdWorker.getWorkerId(), lock);
            
            String token = null;
            try {
                if((token = DistributedLock.methodLock(lock)) == null){
                // 上述是方法级别应用的分布式锁,当系统调用存在该锁的方法时会自动获取;
                    log.error("[NODE ID] : {} , XXL-JOB, [axxx CACHE] -> METHOD LOCK ERROR", IdWorker.getWorkerId());
                    XxlJobLogger.log("[NODE ID] : {} , XXL-JOB [axxx CACHE] -> METHOD LOCK ERROR", IdWorker.getWorkerId());
                    return ReturnT.FAIL;
                    // 返回错误,code为500
                }
                    axxxCache.init();
                    // 本地缓存初始化
                    log.info("[NODE ID] : {} , XXL-JOB, [axxx CACHE] -> AAI相关信息初始化", IdWorker.getWorkerId());
                    log.info("[NODE ID] : {} , XXL-JOB, [axxx CACHE] -> END", IdWorker.getWorkerId());
                    XxlJobLogger.log("[NODE ID] : {} , XXL-JOB, [axxx CACHE] -> END", IdWorker.getWorkerId());
					// 其中IdWorker.getWorkerId()是雪花算法;
            } catch (Exception e){
                ExceptionResponse.returnResponse(e);
                log.error("[NODE ID] : {} , XXL-JOB, [axxx CACHE] -> ERROR", IdWorker.getWorkerId());
                XxlJobLogger.log("[NODE ID] : {} , XXL-JOB [axxx CACHE] -> ERROR:{}", IdWorker.getWorkerId(),e.toString());
                return ReturnT.FAIL;
            }finally {
                DistributedLock.redisUnlock(token);
                // 释放掉之前获取的redis分布式锁;
            }
        return ReturnT.SUCCESS;
        // 返回成功,code为200
    }
}

xxl-job页面配置

1 执行流程

先创建执行器,然后在执行器中创建任务;

在这里插入图片描述
2 创建执行器
在这里插入图片描述
注意:

注册方式:选择自动注册,当测试服务器该项目正常运行后,会自动分配ip以及port,无需填写,并将该port配置到代码中的对应位置。

3 创建任务
在这里插入图片描述

本地docker配置XXL-JOB

参考博客:
https://blog.csdn.net/TM007_/article/details/134186550

使用软件:
docker desktop软件;

配置过程:

打开docker,拉取镜像;
	docker pull xuxueli/xxl-job-admin:2.2.0
运行docker,创建容器:
	docker run -d 
			// 启动一个新的容器 -d 以守护进程模式运行容器
			// params 设置环境变量
	-e PARAMS="--spring.datasource.url=jdbc:mysql://127.0.0.1:3306/xxl_job?useUnicode=true&characterEncoding=UTF-		8&autoReconnect=true&serverTimezone=UTC 
		// 设置数据库URL	
	--spring.datasource.username=root 
		// 数据库 用户名
	--spring.datasource.password=root_pwd 
		// 数据库 密码
	--spring.datasource.driver-class-name=com.mysql.jdbc.Driver" 
		// 数据库驱动类名
	-p  xxxx:8080 
		// 端口设置,将宿主机的xxxx端口映射成容器的8080端口
	-v /home/gxm/docker:/data/applogs 
		// 将宿主主机的地址/home/gxm/docker 挂在到容器的/data/applogs目录中
	--name my-xxl-job-admin-2.4.0  
		// 设置容器的名字
	-d xuxueli/xxl-job-admin:2.4.0
		// 以守护进程模式运行容器
	// 创建容器对应的id d5edf1339ec6bce60843d50216e49fa881ae3fd79dead98e1cdc1b23ee645885
// 注意:将mysql的ip;port配置成本地电脑中docker中的对应内容。

将本地打包的镜像,放入docker desktop中
	docker load -i xxx.tar文件,不支持.jar

结果:
不能运行,失败。

实战

1 @XxlJob注解

@XxlJob(value = "shardFetchKeysIntoCache") 
// 理解:
注解@XxlJob,用于标识一个任务处理方法;
value属性,给这个任务命名;
该属性与xxl-job页面配置中,新建任务--配置任务--JobHandler中的内容;

2 XxlJobHelper的getxxx方法

int shardIndex = XxlJobHelper.getShardIndex();
int shardTotal = XxlJobHelper.getShardTotal(); 
// 理解:
XxlJobHelper.getShardIndex() --》当前执行任务的分片索引;  
XxlJobHelper.getShardTotal() --》当前总的分片数量;

XxlJob是一个开源的分布式任务调度平台,常用于Java应用中实现定时任务的调度和管理。
XxlJobHelper类,应该是任务调度框架中的辅助类,用于处理任务分片。

3 XxlJobLogger和XxlJobHelper的区别与联系

两者在分布式任务调度平台中用于不同的目的,核心区别在于日志记录方面;
XxlJobLogger:
	早期版本,用于日志记录的组件,提供一个简单的接口来记录任务执行时的信息,通常在执行器端记录日志,便于监控和协调;在后续xxx版本中已经被废弃,被XxlJobHelper替代;
	目前已知的是 2.3.0版本是没有该类的,也就是可能从该版本之后就没有了。
XxlJobHelper:
	日志工具,并包含了多种功能的辅助类,旨在简化任务执行过程中的常见操作。

4 雪花算法 snowflakeID

snowflakeID.getWorkerId()
	snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID,共43bit。
	其核心思想是:使用41bit作为毫秒数(当前时间戳-开始时间戳),10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0,表示正数。

思考:
	1 同一个方法中,多次执行snowflakeID.getWorkerId(),其结果是否一致?
		workerId 是由开发者在初始化时设置的一个标识,用于区分不同的机器节点,确保生成的 ID 在不同的机器之间不会冲突。
		只要没有重新初始化Snowflake工程线程,那么该结果是会始终保持一致的;

5 DistributedLock

定义:
	DistributedLock是一个.NET库,基于各种底层技术提供强大且易于使用的分布式互斥体、读写器锁和信号量。
	是一个抽象的概念,表示一种可以跨多个服务实例或进程协调的锁定机制。在分布式环境中,这种锁是必要的,因为它可以确保即使在网络分区或高并发情况下,资源的访问也是安全和有序的。

DistributedLock.methodLock(xxx):
	methodLock 特别指在方法级别应用的分布式锁。这意味着每当调用带有这种方法锁的方法时,系统会自动尝试获取锁。
DistributedLock.redisUnlock(xxx):
	这个方法通常是指在使用Redis作为分布式锁的实现时,用来释放之前获取的锁。
	在分布式系统中,当多个服务实例尝试访问共享资源时,分布式锁可以确保一次只有一个服务实例能够进行修改,从而避免竞态条件和数据不一致性。

6 ReturnT

定义:
	ReturnT<T>是一个通用的返回对象类型,通常在JavaRESTful API、微服务架构或RPC(远程过程调用)框架中使用,比如在dubbo、spring cloud等服务框架中。
	它被设计为一个容器,用于封装方法调用的结果,包括数据、状态码和错误信息等,使得调用者能够清晰地了解调用结果的状态。

ReturnT<T> 通常包含以下几个关键部分:
	泛型参数 T:表示返回的数据类型,它可以是任何类型的对象,包括基本类型、自定义对象、集合等。
	状态码 code:表示调用是否成功,通常0表示成功,非0表示失败或异常。
	消息 msg:描述调用的结果,比如“操作成功”、“参数错误”等。
	数据 data:包含调用的实际结果数据,如果没有数据,可以为空或null

7 调度失败,执行器地址为空

描述:
在这里插入图片描述
分析:

在xxl-job项目以及功能项目中的,xxl.job.accessToken设置成相同的参数,就可以解决该问题。

8 执行结果失败

描述:

java.lang.reflect.InvocationTargetException at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at com.xxl.job.core.handler.impl.MethodJobHandler.execute(MethodJobHandler.java:29) at com.xxl.job.core.thread.JobThread.run(JobThread.java:166) Caused by: java.lang.NullPointerException at com.unicom.autoconfigure.leaf.core.IdWorker.getWorkerId(IdWorker.java:40) at com.unicom.anon.sub.local.dispather.ApplyIpDispather.applyIpCacheHandler(ApplyIpDispather.java:30) ... 6 more

分析:

使用snowflakeID.getWorkerId() 该方法,snowflake生成唯一id;
需要确保如下内容:
1. snowflake配置完成;
	leaf:
  		snowflake:
		    enabled: true
		    name: opn_api
		    zkAddress: 127.0.0.1:2181
2.leaf依赖导入
<dependency>
    <groupId>com.unicom</groupId>
    <artifactId>leaf-spring-boot-starter</artifactId>
    <version>版本号</version>
</dependency>
3.zookeeper
配置zookeeper,用于分配worker ID并保证全局唯一性;

按照上述内容进行配置,还是报错,内容如下:
Caused by: java.lang.NullPointerException
	at com.unicom.autoconfigure.leaf.core.IdWorker.getWorkerId(IdWorker.java:40)
	at com.unicom.anon.sub.local.dispather.ApplyIpDispather.applyIpCacheHandler(ApplyIpDispather.java:30)
	... 6 more
<br>----------- xxl-job job execute end(error) -----------
2024-07-25 14:36:23 [com.xxl.job.core.thread.TriggerCallbackThread#callbackLog]-[197]-[xxl-job, executor TriggerCallbackThread] <br>----------- xxl-job job callback finish.

配置文件修改成:
xxxx:
	leaf:
	  		snowflake:
			    enabled: true
			    name: opn_api
			    zkAddress: 127.0.0.1:2181
这种类型就可以了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值