xxl-job分布式定时任务

1****前言

1.1****业务场景

业务数据同步 ( 线上数据同步到线下,新平台老平台数据的同步 ) ,消息通知,业务数据的补偿。

1.2****什么是定时任务

定时任务是指基于给定的时间点,给定的时间间隔或者给定执行次数自动的执行程序。
任务调度是系统的重要组成部分。
任务调度直接影响着系统的实时性。
任务调度涉及到多线程并发、运行时间规则定制及解析、线程池的维护等诸多方面的工作。

1.2.1****常见的任务框架

常见的分布式任务调度框架有: xxl-job 【美团】、 Elastic-job 【当当】、 saturn 【唯品会】、 lts 【阿
里】、 TBSchedule 、 cronsun 、 Quartz 等。

1.2.2****一般定时任务的不足

不支持集群
不支持任务重试,即任务出错误无解决办法
不支持动态调用规则
无报警机制
不支持生命周期的统一管理
任务数据难以统计

2 XXL-JOB****定时任务

2.1****前言

package com.fanxl.xxljob.task;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class TaskDemo {
/**
* 从数据库中查询数据,插入到另外一个数据
* 程序分两部分:调度模块和任务程序块的代码耦合在一起,
* 1 、如果想改变调度规则,就必须先停止掉服务,才能改变 cron 表达式里的调用规则
* 2 、将 taskdemo 部署多台时,多个线程调用同样的方法,这样的话程序不支持集群部署,可用性无
法保障
*
* 两部分:
* 1 、 Scheduled: 本质上是由 springboot 内置的线程池, 1 个长度的线程池按照定义的时间规则调
用程序
* spring.task.scheduling.pool.size=1
* 2 、开发者自己定义的业务程序
*/
@Scheduled(cron = "0/5 * * * * *")
public void syncData(){
// 查询出的数据
int size = 1000;
for (int i = 0; i < size; i++) {
System.out.println(" 向数据库中插入数据 "+i);
}
}
}
package com.fanxl.xxljob;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
public class XxljobApplication {
public static void main(String[] args) {
SpringApplication.run(XxljobApplication.class, args);
}
}

2.2****设计思想

xxl-job 是一个轻量级的分布式任务调度框架,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。

  1. 将调度行为抽象形成 " 调度中心 " 平台,平台本身并不承担业务逻辑,只负责发起调度请求。
  2. 将任务抽象成分散的 JobHandler ,交由执行器统一管理,执行器负责接收调度请求并执行对应的
    JobHandler 中的业务。
  3. " 调度 " 和 " 任务 " 互相解耦,提高系统整体的稳定性和扩展性。
  4. 将程序分为调度中心【 A 】和执行器【 B 】两部分。执行器指当前应用程序,应用程序中包含 N 个
    具体的任务。相当于【 A 】调用【 B 】里面的一个方法。
  5. 调用机制: 1) HTTP 请求 2) RPC 远程调用
    无论那种调用方式,首先需要知道执行器的地址 ip ,端口。所以在执行器中起了一个注册线程
    【后台线程】。注册线程会向调度中心发送请求【注册服务】。调度中心记下后,方便后期调用执
    行器。
    数据中心:用于持久化的存储,避免下次启动后数据丢失。
  6. 调度中心内置调度器,用来调用执行器,执行器自研 RPC 进行远程调用 , 执行器会注册到调度中
    心,调度中心基于地址和端口进行 RPC 的远程调用。双向。
  7. 调度中心调用执行器中的某个具体任务之后,执行器接收到服务之后,进行调度,执行某个具体的
    方法【 JobHandler 】,而后将执行结果传给调度中心。
  8. 调用结果执行完后执行回调服务,回调服务将结果记录,形成调度日志。

2.3****核心组件

  1. 调度模块 ( 调度中心)
    负责管理调度信息,按照调度配置发出调度请求,本身不承担业务代码。
    调度系统与任务解耦,提高了系统可用性与稳定性,同时调度系统性能不在受限于任务模块。
    支持可视化,简单且动态的管理调度信息,包括任务新建,更新,删除, GLUE 开发和任务报警
    等,所有上述操作都会实时生效,同时支持监控调度结果及执行日志,支持执行器 Failover 【故障
    转移】。
  2. 执行模块 ( 执行器 )
    负责接受调度请求并执行任务逻辑。
    任务模块专注于任务的执行等操作,开发和维护更加简单和高效。
    接受 " 调度中心 " 的执行请求,终止请求和日志请求等。

2.4****特点

官网: https://www.xuxueli.com/xxl-job/
1 、简单:支持通过 Web 页面对任务进行 CRUD 操作,操作简单,一分钟上手。
2 、动态:支持动态修改任务状态、启动 / 停止任务,以及终止运行中任务,即时生效。
3 、调度中心 HA (中心式):调度采用中心式设计, " 调度中心 " 自研调度组件并支持集群部署,可保证
调度中心 HA ;【 HA: 高可用】由于调度的中心式设计,所以调度中心在部署时,需要 所有的调度中心
访问同一个 DB( 数据库 )
4 、执行器 HA (分布式):任务分布式执行,任务 " 执行器 " 支持集群部署,可保证任务执行 HA 。【
调用不执行
5 、注册中心 : 执行器会周期性自动注册任务 , 调度中心将会自动发现注册的任务并触发执行。同时,也
支持手动录入执行器地址。
6 、自定义任务参数:支持在线配置调度任务入参,即时生效;【当任务失败时,可以手动设置参数使
任务再次执行】
7 、任务依赖:支持配置子任务依赖,当父任务执行结束且执行成功后将会主动触发一次子任务的执行 ,
多个子任务用逗号分隔。
8 、弹性扩容缩容:一旦有新执行器机器上线或者下线,下次调度时将会重新分配任务。
9 、路由策略:执行器集群部署时提供丰富的路由策略,包括:第一个、最后一个、轮询【第一次调用
执行器 1 ,第二次调用执行器 2 】、随机、一致性 HASH 【 A 任务永远执行 1 ,或者永远执行 2 】、最不
经常使用、最近最久未使用、故障转移【当第一次执行,执行执行器 1 ,当第一次执行失败时,可以转
而执行执行器 2 】,忙碌转移【当访问执行器 1 时,可能比较忙碌,此时可以去访问执行器 2 】等。
10 、故障转移:任务路由策略选择 " 故障转移 " 情况下,如果执行器集群中某一台机器故障,将会自动
Failover 切换到一台正常的执行器发送调度请求。
11 、阻塞处理策略:调度过于密集执行器来不及处理时的处理策略。
策略包括:
1 )单机串行(默认):即等待,等待上一个执行完再执行;
2 )丢弃后续调度:即一个任务的后面还有任务时,丢掉后面的任务;
3 )覆盖之前调度:如果现在有一个任务 A 在执行,后面又一个任务 A 在执行,此时可以停掉前面的 A
任务,直接执行第二次的新的 A 任务。
12 、事件触发:除了 "Cron 方式 " 和 " 任务依赖方式 " 触发任务执行之外,支持基于事件的触发任务方
式。调度中心提供触发任务单次执行的 API 服务,可根据业务事件灵活触发。【手动触发和父子任务】
13 、任务进度监控:支持实时监控任务进度;
14 、 Rolling 实时日志:支持在线查看调度结果,并且支持以 Rolling 方式实时查看执行器输出的完整的
执行日志;

3 XXL-JOB****实战

3.1 XXL-JOB****入门使用

3.1.1****下载源码

  1. 码云地址: https://gitee.com/xuxueli0323/xxl-job

3.1.2****初始化数据库

  1. 用 IDEA 将 maven 项目导入到本地
  2. 初始化数据库,运行 doc/db/tables_xxl_job.sql 中的 sql 生成数据库和表

右键数据库点击运行 SQL 文件,选择 Sql 脚本对应文件

3.1.3****数据库介绍

  • xxl_job_lock :任务调度锁表;
  • xxl_job_group :执行器信息表,维护任务执行器信息;
  • xxl_job_info :调度扩展信息表: 用于保存 XXL-JOB 调度任务的扩展信息,如任务分组、任务名、机器
    地址、执行器、执行入参和报警邮件等等;
  • xxl_job_log :调度日志表: 用于保存 XXL-JOB 任务调度的历史信息,如调度结果、执行结果、调度入
    参、调度机器和执行器等等;
  • xxl_job_log_report :调度日志报表:用户存储 XXL-JOB 任务调度日志的报表,调度中心报表功能页面
    会用到;
  • xxl_job_logglue :任务 GLUE 日志:用于保存 GLUE 更新历史,用于支持 GLUE 的版本回溯功能;
  • xxl_job_registry :执行器注册表,维护在线的执行器和调度中心机器地址信息;
  • xxl_job_user :系统用户表;权限设计比较弱,若设置权限管理需要二次开发。

3.1.4****编译部署调度中心

3.1.4.1****项目介绍
3.1.4.2****配置管理数据源

修改 application.properties 文件的配置
文件路径: /xxl-job/xxl-job-admin/src/main/resources/application.properties

3.1.4.3****访问管理界面

启动服务后访问网址: http://localhost:8080/xxl-job-admin/

3.1.5****部署架构图


用一个调度中心部署多个节点,多个调度中心必须使用同一个 Mysql 数据库,多个节点前面使用负载均
衡器,所有的任务执行器也可以部署多个节点,任务执行器配置调度中心的地址的时候,配置负载均衡
器的地址。

3.1.6****创建执行器

3.1.6.1****引入核心依赖

<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>2.3.1</version>
</dependency>

3.1.6.2****编辑配置文件

将官方代码示例文件 application.properties 和 logback.xml 中的内容拷贝到执行器项目中,根据需要
修改 application.properties 文件中的配置

web port 当前应用端口

server.port=8081

no web

#spring.main.web-environment=false

log config 日志名称

logging.config=classpath:logback.xml

注册地址

xxl-job admin address list, such as "http://address" or

"http://address01,http://address02"
xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin

xxl-job, access token

xxl.job.accessToken=default_token

xxl-job executor appname 执行器名称,同一应用多个节点使用同样的名称

xxl.job.executor.appname=xxl-job-executor-sample

执行器的 ip 和 address 可以动态的被发现

xxl-job executor registry-address: default use address to registry ,

otherwise use ip:port if address is null
xxl.job.executor.address=

xxl-job executor server-info

xxl.job.executor.ip=

执行器内部端口 rpc 内部调用端口

xxl.job.executor.port=8181

日志存储位置

xxl-job executor log-path

xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler

xxl-job executor log-retention-days

xxl.job.executor.logretentiondays=30

3.1.6.3****配置类

新建 core.config 目录,并新建类 XxlJobConfig ,将官方文档中的代码拷入。

java 复制代码
package com.fanxl.xxljobdemo.config.XxlJobConfig;
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
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;
/**
* @description:
* @author: fanxl
* @date: 2023/4/26 11:07
* @param:
* @return:
**/
@Configuration
public class XxlJobConfig {
private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);
@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.address}")
private String address;
@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;
@Bean
public XxlJobSpringExecutor xxlJobExecutor() {
logger.info(">>>>>>>>>>> xxl-job config init.");
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
xxlJobSpringExecutor.setAppname(appname);
xxlJobSpringExecutor.setAddress(address);
xxlJobSpringExecutor.setIp(ip);
xxlJobSpringExecutor.setPort(port);
xxlJobSpringExecutor.setAccessToken(accessToken);
xxlJobSpringExecutor.setLogPath(logPath);
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
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();
*/
}
3.1.6.4编写xxl-job****任务

在 src/main/java/com/fanxl / 下新建一个包 job, 并在包下新建配置类: xxljobdemo.job

java 复制代码
package com.fanxl.xxljobdemo.job;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import org.springframework.stereotype.Component;
@Component //定义Spring管理Bean(也就是将标注@Component注解的类交由spring管理)
public class DemoXxlJob {
/**
* @description:第一个xxl-job任务
* @author: fanxl
* @date: 2023/4/26 11:16
* @param: []
* @return: com.xxl.job.core.biz.model.ReturnT
**/
//value:任务名称
@XxlJob(value = "demoTask")
public ReturnT demoTask(){
System.out.println("Hello xxl job");
//调度结果
return ReturnT.SUCCESS;
}
}

3.1.7****配置定时任务

3.1.7.1****配置执行


注册方式:后台线程自动注册 / 手动录入。
当注册方式为自动注册时,会自动生成 OnLine 机器地址。【需要先在配置文件中配置执行器的名称
xxl.job.executor.appname=xxl-job-executor-sample 】
注册节点的端口号为配置文件中设置的执行器内部调用的端口号。

3.1.7.2****配置具体定时任务

方法上加注解 @XxlJob,value 为任务的名称。
JobHandler 的值为 DemoXxlJob 中指定的任务名称,即 value 的值。

3.1.7.3****手动触发执行
3.1.7.4****结果示例

3.2****路由策略

假设有三台执行器: A1 , A2 , A3
第一个:默认调用 A1
最后一个:默认调用 A3
轮询:第一次调用时调用 A1 ,第二次调用时调用 A2 ,第三次调用时调用 A3
随机:随机调用 A1 , A2 , A3
步骤一: 创建 xxl-job 任务

java 复制代码
package com.fanxl.xxljobdemo.job;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Component;
/**
*@Author: fanxl
*@CreateTime: 2023-04-26 11:14
*/
@Component //定义Spring管理Bean(也就是将标注@Component注解的类交由spring管理)
@Log4j2
public class DemoXxlJob {
/**
* @description:第一个xxl-job任务
* @author: fanxl
* @date: 2023/4/26 11:16
* @param: []
* @return: com.xxl.job.core.biz.model.ReturnT
**/
//value:任务名称
@XxlJob(value = "demoTask")
public ReturnT demoTask(){
System.out.println("Hello xxl job");
//调度结果
return ReturnT.SUCCESS;
}
/**
* @description:演示:调度策略:第一个执行器
* @author: fanxl
* @date: 2023/4/26 13:35
* @param: []
* @return: com.xxl.job.core.biz.model.ReturnT
**/
@XxlJob("fisrtTask")
public ReturnT firstTask(){
log.info("========演示调度策略:第一个执行器");
return ReturnT.SUCCESS;
}
/**
* @description:演示:调度策略:最后一个执行器
* @author: fanxl
* @date: 2023/4/26 13:37
* @param: []
* @return: com.xxl.job.core.biz.model.ReturnT
**/
@XxlJob("lastTask")
public ReturnT lastTask(){
log.info("========演示调度策略:最后一个执行器");
return ReturnT.SUCCESS;
}
/**
* @description:演示:调度策略:轮询
* @author: fanxl
* @date: 2023/4/26 13:38
* @param: []
* @return: com.xxl.job.core.biz.model.ReturnT
**/
@XxlJob("pollTask")
public ReturnT pollTask(){
log.info("========演示调度策略:轮询执行器");
return ReturnT.SUCCESS;
}
/**
* @description:演示:调度策略:随机
* @author: fanxl
* @date: 2023/4/26 13:39
* @param: []
* @return: com.xxl.job.core.biz.model.ReturnT
**/
@XxlJob("randomTask")
public ReturnT randomTask(){
log.info("========演示调度策略:随机执行器");
return ReturnT.SUCCESS;
}
/**
* @description:演示:调度策略:hash策略
* @author: fanxl
* @date: 2023/4/26 13:39
* @param: []
* @return: com.xxl.job.core.biz.model.ReturnT
**/
@XxlJob("hashTask")
public ReturnT hashTask(){
log.info("========演示调度策略:哈希执行器");
return ReturnT.SUCCESS;
}
}

**步骤二:**编辑启动项配置和端口

  1. 复制原启动项,更改名称;
  2. 修改配置文件中的应用端口和内部调用端口

    步骤三: 创建任务
    1、在步骤二启动服务后,可以在执行器管理处看见已经生成三个注册节点。

2、在任务管理处创建对应的任务

步骤四: 手动执行任务测试
结果 :
1 、当路由策略为第一个时,只有 8081 的服务被调用了。

相关推荐
liuyunshengsir26 分钟前
Spring Boot 使用 Micrometer 集成 Prometheus 监控 Java 应用性能
java·spring boot·prometheus
路上阡陌35 分钟前
Java学习笔记(二十四)
java·笔记·学习
何中应44 分钟前
Spring Boot中选择性加载Bean的几种方式
java·spring boot·后端
苏苏大大1 小时前
zookeeper
java·分布式·zookeeper·云原生
wclass-zhengge1 小时前
03垃圾回收篇(D3_垃圾收集器的选择及相关参数)
java·jvm
涛ing1 小时前
23. C语言 文件操作详解
java·linux·c语言·开发语言·c++·vscode·vim
5xidixi2 小时前
Java TCP协议(2)
java·tcp/ip
2013crazy2 小时前
Java 基于 SpringBoot+Vue 的校园兼职平台(附源码、部署、文档)
java·vue.js·spring boot·兼职平台·校园兼职·兼职发布平台
小高不明2 小时前
仿 RabbitMQ 的消息队列3(实战项目)
java·开发语言·spring·rabbitmq·mybatis
兩尛2 小时前
订单状态定时处理、来单提醒和客户催单(day10)
java·前端·数据库