分布式调度XXL-JOB急速入门

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
日志服务 SLS,月写入数据量 50GB 1个月
简介: 分布式调度XXL-JOB急速入门

1.业界分布式定时任务框架简介

8fc0b20e27524136a12356f9f87b1391.jpg

  • Quartz
  • Quartz关注点在于定时任务而并非是数据,并没有一套根据数据化处理而定的流程
  • 虽然可以实现数据库作业的高可用,但是缺少了分布式的并行调度功能,相对弱点
  • 不支持任务分片、没UI界面管理,并行调度、失败策略等也缺少
  • TBSchedule
  • 这个是阿里早期开源的分布式任务调度系统,使用的是timer而不是线程池执行任务调度,使用timer在处理异常的时候是有缺陷的,但TBSchedule的作业类型比较单一,文档也缺失得比较严重
  • 目前阿里内部使用的是ScheduleX
  • Elastic-job
  • 当当开发的分布式任务调度系统,功能强大,采用的是zookeeper实现分布式协调,具有高可用与分片。
  • 2020年6月,ElasticJob的四个子项目已经正式迁入Apache仓库
  • 由 2 个相互独立的子项目 ElasticJob-Lite 和 ElasticJob-Cloud 组成
  • ElasticJob-Lite 定位为轻量级无中心化解决方案,使用jar的形式提供分布式任务的协调服务;

ElasticJob-Cloud 使用 Mesos 的解决方案,额外提供资源治理、应用分发以及进程隔离等服务

地址:https://shardingsphere.apache.org/elasticjob/index_zh.html

XXL-JOB

  • 大众点评的员工徐雪里在15年发布的分布式任务调度平台,是轻量级的分布式任务调度框架,目标是开发迅速、简单、清理、易扩展; 老版本是依赖quartz的定时任务触发,在v2.1.0版本开始 移除quartz依赖

常规对比图

对比项 XXL-JOB elastic-job
并行调度 调度系统多线程并行 任务分片的方式并行
弹性阔容 使用Quartz基于数据库分布式功能 通过zookeeper保证
高可用 通过DB锁保证 通过zookeeper保证
阻塞策略 单机串行/丢弃后续的调度/覆盖之前的调度 执行超过zookeeper的session timeout时间的话,会被清除,重新进行分片
动态分片策略 以执行器为维度进行分片、支持动态的扩容 平均分配/作业名hash分配/自定义策略
失败处理策略 失败告警/失败重试 执行完毕后主动获取未分配分片任务 服务器下线后主动寻找可以用的服务器执行任务
监控 支持 支持
日志 支持 支持

2.分布式调度XXL-JOB核心特性

(1)XXL-JOB的设计思想

  • 将调度行为抽象形成“调度中心”公共平台,而平台自身并不承担业务逻辑,“调度中心”负责发起调度请求。
  • 将任务抽象成分散的JobHandler,交由“执行器”统一管理
  • “执行器”负责接收调度请求并执行对应的JobHandler中业务逻辑。
  • 因此,“调度”和“任务”两部分可以相互解耦,提高系统整体稳定性和扩展性

(2)XXL-JOB架构图

  • 调度中心
  • 负责管理调度的信息,按照调度的配置来发出调度请求。
  • 支持可视化、简单的动态管理调度信息,包括新建、删除、更新等,这些操作都会实时生效,同时也支持监控调度结果及执行日志。
  • 执行器
  • 负责接受请求并且执行任务的逻辑。任务模块专注于任务的执行操作等等,使得开发和维护更加的简单与高效。
  • fd58006f7f2d4bc0a52dc8f4c4e8ed83.jpg

(3)XXL-JOB具有哪些特性

  • 调度中心HA(中心式):调度采用了中心式进行设计,“调度中心”支持集群部署,可保证调度中心HA
  • 执行器HA(分布式):任务分布式的执行,任务执行器支持集群部署,可保证任务执行HA
  • 触发策略:有Cron触发、固定间隔触发、固定延时触发、API事件触发、人工触发、父子任务触发
  • 路由策略:执行器在集群部署的时候提供了丰富的路由策略,如:第一个、最后一个、轮询、随机、一致性HASH、最不经常使用LFU、最久未使用LRU、故障转移等等
  • 故障转移:如果执行器集群的一台机器发生故障,会自动切换到一台正常的执行器发送任务调度
  • Rolling实时日志的监控:支持rolling方式查看输入的完整执行日志
  • 脚本任务:支持GLUE模式开发和运行脚本任务,包括Shell、python、node.js、php等等类型脚本

3.Docker部署MySQL8.0

(1)拉取Mysql镜像

docker pull mysql:latest


61acf774fc4f4fd3a36b593e4b83a328.jpg

(2)启动MySQL容器

docker run -itd --name mysql-lixiang -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql
# 查看容器是否启动
docker ps 

c5a60c6250584b83b77525baa018223e.jpg

(3)可视化工具连接


74016bc7b399418f9001ec8a40d604d7.jpg


20a95fdb4eba47ce90a20e4d471aa5d9.jpg


CREATE TABLE `xxl_job_group` (
  `id` int NOT NULL AUTO_INCREMENT,
  `app_name` varchar(64) NOT NULL COMMENT '执行器AppName',
  `title` varchar(12) NOT NULL COMMENT '执行器名称',
  `address_type` tinyint NOT NULL DEFAULT '0' COMMENT '执行器地址类型:0=自动注册、1=手动录入',
  `address_list` varchar(512) DEFAULT NULL COMMENT '执行器地址列表,多地址逗号分隔',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
CREATE TABLE `xxl_job_info` (
  `id` int NOT NULL AUTO_INCREMENT,
  `job_group` int NOT NULL COMMENT '执行器主键ID',
  `job_cron` varchar(128) NOT NULL COMMENT '任务执行CRON',
  `job_desc` varchar(255) NOT NULL,
  `add_time` datetime DEFAULT NULL,
  `update_time` datetime DEFAULT NULL,
  `author` varchar(64) DEFAULT NULL COMMENT '作者',
  `alarm_email` varchar(255) DEFAULT NULL COMMENT '报警邮件',
  `executor_route_strategy` varchar(50) DEFAULT NULL COMMENT '执行器路由策略',
  `executor_handler` varchar(255) DEFAULT NULL COMMENT '执行器任务handler',
  `executor_param` varchar(512) DEFAULT NULL COMMENT '执行器任务参数',
  `executor_block_strategy` varchar(50) DEFAULT NULL COMMENT '阻塞处理策略',
  `executor_timeout` int NOT NULL DEFAULT '0' COMMENT '任务执行超时时间,单位秒',
  `executor_fail_retry_count` int NOT NULL DEFAULT '0' COMMENT '失败重试次数',
  `glue_type` varchar(50) NOT NULL COMMENT 'GLUE类型',
  `glue_source` mediumtext COMMENT 'GLUE源代码',
  `glue_remark` varchar(128) DEFAULT NULL COMMENT 'GLUE备注',
  `glue_updatetime` datetime DEFAULT NULL COMMENT 'GLUE更新时间',
  `child_jobid` varchar(255) DEFAULT NULL COMMENT '子任务ID,多个逗号分隔',
  `trigger_status` tinyint NOT NULL DEFAULT '0' COMMENT '调度状态:0-停止,1-运行',
  `trigger_last_time` bigint NOT NULL DEFAULT '0' COMMENT '上次调度时间',
  `trigger_next_time` bigint NOT NULL DEFAULT '0' COMMENT '下次调度时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
CREATE TABLE `xxl_job_lock` (
  `lock_name` varchar(50) NOT NULL COMMENT '锁名称',
  PRIMARY KEY (`lock_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
CREATE TABLE `xxl_job_log` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `job_group` int NOT NULL COMMENT '执行器主键ID',
  `job_id` int NOT NULL COMMENT '任务,主键ID',
  `executor_address` varchar(255) DEFAULT NULL COMMENT '执行器地址,本次执行的地址',
  `executor_handler` varchar(255) DEFAULT NULL COMMENT '执行器任务handler',
  `executor_param` varchar(512) DEFAULT NULL COMMENT '执行器任务参数',
  `executor_sharding_param` varchar(20) DEFAULT NULL COMMENT '执行器任务分片参数,格式如 1/2',
  `executor_fail_retry_count` int NOT NULL DEFAULT '0' COMMENT '失败重试次数',
  `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间',
  `trigger_code` int NOT NULL COMMENT '调度-结果',
  `trigger_msg` text COMMENT '调度-日志',
  `handle_time` datetime DEFAULT NULL COMMENT '执行-时间',
  `handle_code` int NOT NULL COMMENT '执行-状态',
  `handle_msg` text COMMENT '执行-日志',
  `alarm_status` tinyint NOT NULL DEFAULT '0' COMMENT '告警状态:0-默认、1-无需告警、2-告警成功、3-告警失败',
  PRIMARY KEY (`id`),
  KEY `I_trigger_time` (`trigger_time`),
  KEY `I_handle_code` (`handle_code`)
) ENGINE=InnoDB AUTO_INCREMENT=89580 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
CREATE TABLE `xxl_job_log_report` (
  `id` int NOT NULL AUTO_INCREMENT,
  `trigger_day` datetime DEFAULT NULL COMMENT '调度-时间',
  `running_count` int NOT NULL DEFAULT '0' COMMENT '运行中-日志数量',
  `suc_count` int NOT NULL DEFAULT '0' COMMENT '执行成功-日志数量',
  `fail_count` int NOT NULL DEFAULT '0' COMMENT '执行失败-日志数量',
  PRIMARY KEY (`id`),
  UNIQUE KEY `i_trigger_day` (`trigger_day`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=53 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
CREATE TABLE `xxl_job_logglue` (
  `id` int NOT NULL AUTO_INCREMENT,
  `job_id` int NOT NULL COMMENT '任务,主键ID',
  `glue_type` varchar(50) DEFAULT NULL COMMENT 'GLUE类型',
  `glue_source` mediumtext COMMENT 'GLUE源代码',
  `glue_remark` varchar(128) NOT NULL COMMENT 'GLUE备注',
  `add_time` datetime DEFAULT NULL,
  `update_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
CREATE TABLE `xxl_job_registry` (
  `id` int NOT NULL AUTO_INCREMENT,
  `registry_group` varchar(50) NOT NULL,
  `registry_key` varchar(255) NOT NULL,
  `registry_value` varchar(255) NOT NULL,
  `update_time` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `i_g_k_v` (`registry_group`,`registry_key`,`registry_value`)
) ENGINE=InnoDB AUTO_INCREMENT=165 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
CREATE TABLE `xxl_job_user` (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(50) NOT NULL COMMENT '账号',
  `password` varchar(50) NOT NULL COMMENT '密码',
  `role` tinyint NOT NULL COMMENT '角色:0-普通用户、1-管理员',
  `permission` varchar(255) DEFAULT NULL COMMENT '权限:执行器ID列表,多个逗号分割',
  PRIMARY KEY (`id`),
  UNIQUE KEY `i_username` (`username`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

4.XXL-JOB数据库脚本介绍

xxl_job_group:执行器信息表,用于维护任务执行器的信息

xxl_job_info:调度扩展信息表,主要是用于保存xxl-job的调度任务的扩展信息,比如说像任务分组、任务名、机器的地址等等

xxl_job_lock:任务调度锁表

xxl_job_log:日志表,主要是用在保存xxl-job任务调度历史信息,像调度结果、执行结果、调度入参等等

xxl_job_log_report:日志报表,会存储xxl-job任务调度的日志报表,会在调度中心里的报表功能里使用到

xxl_job_logglue:任务的GLUE日志,用于保存GLUE日志的更新历史变化,支持GLUE版本的回溯功能

xxl_job_registry:执行器的注册表,用在维护在线的执行器与调度中心的地址信息

xxl_job_user:系统的用户表

5.Docker部署XXL-JOB服务端

docker run -d -e PARAMS="--spring.datasource.url=jdbc:mysql://192.168.139.200:3306/xxl_job?Unicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai \
--spring.datasource.username=root \
--spring.datasource.password=123456 \
--xxl.job.accessToken=lixiang123." \
-p 8080:8080 \
--name xxl-job-admin --restart=always xuxueli/xxl-job-admin:2.2.0

2d4dda32677144c089f6acf275a62d84.jpg

  • 访问xxl-job-admin可视化界面 http://ip:8080/xxl-job-admin/toLogin



a559565d7d2f46e29b043b525f61ce34.jpg

  • 账号/密码:admin/123456


6a047bf7a3494ed594e26fe8a66a440e.jpg


6.XXL-JOB UI菜单模块介绍

(1)运行报表

  • 任务数量:能够看到调度中心运行的任务数量
  • 调度次数:调度中心所触发的调度次数
  • 执行器数量:在整个调度中心中,在线的执行器数量有多少


e20064a89bae405f8776796f01c68a29.jpg

(2)任务管理(配置执行任务)

  • 示例执行器:所用到的执行器
  • 任务描述:概述该任务是做什么的
  • 路由策略:

第一个:选择第一个机器

最后一个:选择最后一个机器

轮询:依次选择执行

随机:随机选择在线的机器

一致性HASH:每个任务按照Hash算法固定选择某一台机器,并且所有的任务均匀散列在不同的机器上

最不经常使用:使用频率最低的机器优先被使用

最近最久未使用:最久未使用的机器优先被选举

故障转移:按照顺序依次进行心跳检测,第一个心跳检测成功的机器选定为目标的执行器并且会发起任务调度

忙碌转移:按照顺序来依次进行空闲检测,第一个空闲检测成功的机器会被选定为目标群机器,并且会发起任务调度

分片广播:广播触发对于集群中的所有机器执行任务,同时会系统会自动传递分片的参数

Cron:执行规则

调度过期策略:调度中心错过调度时间的补偿处理策略,包括:忽略、立即补偿触发一次等

JobHandler:定义执行器的名字

阻塞处理策略:

单机串行:新的调度任务在进入到执行器之后,该调度任务进入FIFO队列,并以串行的方式去进行

丢弃后续调度:新的调度任务在进入到执行器之后,如果存在相同的且正在运行的调度任务,本次的调度任务请求就会被丢弃掉,并且标记为失败

覆盖之前的调度:新的调度任务在进入到执行器之后,如果存在相同的且正在运行的调度任务,就会终止掉当前正在运行的调度任务,并且清空队列,运行新的调度任务。

子任务ID:输入子任务的任务id,可填写多个

任务超时时间:添加任务超时的时候,单位s,设置时间大于0的时候就会生效

失败重试次数:设置失败重试的次数,设置时间大于0的时候就会生效

负责人:填写该任务调度的负责人

报警邮件:出现报警,则发送邮件

216d847eac5d4f269159a4ee4c86d77a.jpg


921ece8f492f4178b67184e32c7d6ebd.jpg

(3)执行器管理

  • 这里是配置执行器,等待执行器启动的时候都会被调度中心监听加入到地址列表


cde5aab5e38342dba92b3a3cb9ce3a40.jpg


02f0d6394c2847a492f3071d0fc531d5.jpg

(4)调度日志

  • 这里是查看调度的日志,根据日志来查看任务具体的执行情况是怎样的

850c42326b0847beb2f4a58b9f98f55a.jpg

a3d8fad59d93493e9e2306f358b12792.jpg

(5)用户管理

  • 对用户的一些增删改查操作

a239ef9607c14fe7860aaa95700653b7.jpg

7.SpringBoot整合XXL-JOB

(1)新建maven项目,添加依赖

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.7</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
            <scope>compile</scope>
        </dependency>
        <!--添加xxl-job依赖-->
        <dependency>
            <groupId>com.xuxueli</groupId>
            <artifactId>xxl-job-core</artifactId>
            <version>2.3.0</version>
        </dependency>
    </dependencies>

(2)创建运行主类

/**
 * xxl-job启动类
 */
@SpringBootApplication
public class JobApplication {
    public static void main(String[] args) {
        SpringApplication.run(JobApplication.class, args);
    }
}

(3)增加logback.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false" scan="true" scanPeriod="1 seconds">
    <contextName>logback</contextName>
    <property name="log.path" value="./data/logs/xxl-job/app.log"/>
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
    <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${log.path}</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}.%d{yyyy-MM-dd}.zip</fileNamePattern>
        </rollingPolicy>
        <encoder>
            <pattern>%date %level [%thread] %logger{36} [%file : %line] %msg%n
            </pattern>
        </encoder>
    </appender>
    <root level="info">
        <appender-ref ref="console"/>
        <appender-ref ref="file"/>
    </root>
</configuration>

(4)增加配置文件application.properties

# 定义服务名
spring.application.name=job-server
# 定义服务端口
server.port=8081
#xxl-job配置
logging.config=classpath:logback.xml
#调度中心部署地址,多个配置逗号分隔 "http://address01,http://address02"
xxl.job.admin.addresses=http://192.168.139.200:8080/xxl-job-admin
# 执行器app名称,和控制台那边配置一样的名称,不然注册不上去
xxl.job.executor.appname=lixiang-test
# [选填]执行器注册:优先使用该配置作为注册地址,为空时使用内嵌服务 ”IP:PORT“ 作为注册地址。
# 从而更灵活的支持容器类型执行器动态IP和动态映射端口问题。
xxl.job.executor.address=
xxl.job.accessToken=lixiang123.
#[选填]执行器IP :默认为空表示自动获取IP(即springboot容器的ip和端口,可以自动获取,也可以指定),多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯实用;地址信息用于 "执行器注册" 和 "调度中心请求并触发任务",
xxl.job.executor.ip=
# [选填]执行器端口号:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;
xxl.job.executor.port=9999
#执行器日志文件存储路径,需要对该路径拥有读写权限;为空则使用默认路径
xxl.job.executor.logpath=./data/logs/xxl-job/executor
#执行器日志保存天数
xxl.job.executor.logretentiondays=30

1f43ea4111cc4e788fef46521f0e69ab.jpg

(5)增加XxlJobConfig配置类

@Configuration
public class XxlJobConfig {
    /**
     * 定义Logger
     */
    private final Logger log = 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;
    public XxlJobConfig() {
    }
    /**
     * 配置xxl-job
     * @return
     */
    @Bean
    public XxlJobSpringExecutor xxlJobExecutor() {
        log.info("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);
        return xxlJobSpringExecutor;
    }
}

(6)启动验证


aa14b96bd91940f396c113de73d29a9f.jpg

(7)创建xxl-job定时任务

/**
 * 测试Job
 */
@Component
public class TestJob {
    private final Logger log = LoggerFactory.getLogger(TestJob.class);
    @XxlJob(value = "TestJob",init = "init",destroy = "destroy")
    public ReturnT<String> execute(String param){
        log.info("TestJob execute 任务方法触发成功");
        return ReturnT.SUCCESS;
    }
    private void init(){
        log.info("执行 TestJob init >>>>>");
    }
    private void destroy(){
        log.info("执行 TestJob destroy >>>>>");
    }
}

(8)xxl-job ui配置任务

671ecdbbc0ec40858887dee39a16c5fb.jpg

(9)运行JOB,启动SpringBoot项目


082485f1a6bc43cdb047da25039db20b.jpg


9a340b180e4842b183bbdfd7a935d077.jpg

(10)路由策略种类

第一个:当选择该策略时,会选择执行器注册地址的第一台机器执行,如果第一台机器出现故障,则调度任务失败。


最后一个:当选择该策略时,会选择执行器注册地址的最后一台机器执行,如果最后一台机器出现故障,则调度任务失败。


轮询:当选择该策略时,会按照执行器注册地址轮询分配任务,如果其中一台机器出现故障,调度任务失败,任务不会转移。


随机:当选择该策略时,会按照执行器注册地址随机分配任务,如果其中一台机器出现故障,调度任务失败,任务不会转移。


一致性HASH:当选择该策略时,每个任务按照Hash算法固定选择某一台机器。如果那台机器出现故障,调度任务失败,任务不会转移。


最不经常使用:当选择该策略时,会优先选择使用频率最低的那台机器,如果其中一台机器出现故障,调度任务失败,任务不会转移。


最近最久未使用:当选择该策略时,会优先选择最久未使用的机器,如果其中一台机器出现故障,调度任务失败,任务不会转移。


故障转移:当选择该策略时,按照顺序依次进行心跳检测,如果其中一台机器出现故障,则会转移到下一个执行器,若心跳检测成功,会选定为目标执行器并发起调度。


忙碌转移:当选择该策略时,按照顺序依次进行空闲检测,如果其中一台机器出现故障,则会转移到下一个执行器,若空闲检测成功,会选定为目标执行器并发起调度。


分片广播:当选择该策略时,广播触发对应集群中所有机器执行一次任务,同时系统自动传递分片参数;可根据分片参数开发分片任务。如果其中一台机器出现故障,则该执行器执行失败,不会影响其他执行器。

8.分布式调度参数传递

(1)在UI上传递参数

9dd252fa68fe49bab1abf0be356e7bc3.jpg

(2)代码中修改

String jobParam = XxlJobHelper.getJobParam();


7ce5a35a07e34fc481aecf4fd96f4ed0.jpg

(3)接收JSONaca9f713ee1a41d6aee39edc25ef0ec5.jpg

5e209388f5fe4da7ab9ed2a8cde4a74e.jpg


9.分布式调度日志埋点

02730628a1c84ab6b417c89005473577.jpg

(1)代码配置

XxlJobHelper.log("我是业务埋点日志,方便查询错误");

c87f5be1f31442d29ed207cffe24adc0.jpg


435f3ac742fe4d6faea2503f4d8f6319.jpg

10.自定义返回执行成功或失败

  • 默认任务结果为 “成功” 状态,不需要主动设置
  • 自主设置任务结果(会出现在【执行备注】里面)
  • 如想设置任务结果为失败,可以通过 "XxlJobHelper.handleFail
  • 如想设置任务结果为成功,handleSuccess
@XxlJob(value = "TestJob",init = "init",destroy = "destroy")
    public void execute(){
        log.info("TestJob execute 任务方法触发成功");
        String jobParam = XxlJobHelper.getJobParam();
        log.info("TestJob 接收到的参数:{}",jobParam);
        XxlJobHelper.log("我是业务埋点日志,方便查询错误");
        if("测试成功".equals(jobParam)){
            XxlJobHelper.handleSuccess();
        }else if("测试失败".equals(jobParam)){
            XxlJobHelper.handleFail();
        }
    }

0c249c8a9d4a4deb9eb34b2ec19a1cc7.jpg

11.XXL-Job高可用方案

  • HA/集群
  • 为了避免单点故障,任务调度系统通常需要通过集群实现系统高可用


由于任务调度系统的特殊性,“调度”和“任务”两个模块需要均支持集群部署,由于职责不同,因此各自集群侧重点也有有所不同。

调度中心集群

目标为避免调度模块单点故障,集群节点需要通过锁或命名服务保证单个任务的单次触发,只在其中一个节点上生效,以防止任务的重复触发。

执行器集群

目标为避免任务模块单点故障,进一步可以通过自定义路由策略实现Failover等高级功能,从而在执行器某台机器节点故障时自动转移不会影响到任务的正常触发执行

高可用集群架构



51d225ef71224c25bc9b2b8b04e34da4.jpg

12.XXL-Job分片任务处理

(1)什么是分片任务

  • 执行器集群部署,如果任务的路由策略选择【分片广播】,一次任务调度将会【广播触发】对应集群中所有执行器执行一次任务,同时系统自动传递分片参数,执行器可根据分片参数开发分片任务
  • 需要处理的海量数据,以执行器为划分,每个执行器分配一定的任务数,并行执行
  • XXL-Job支持动态扩容执行器集群,从而动态增加分片数量,到达更快处理任务
  • 分片的值是调度中心分配的


b11d1202e02943f78d41456e2425d3d3.jpg

(2)案例

  • 模拟100个用户数据执行定时,分片处理
/**
 * 测试Job
 */
@Component
public class ShardingJob {
    private final Logger log = LoggerFactory.getLogger(ShardingJob.class);
    @XxlJob(value = "shardingJob")
    public void execute(){
        log.info("shardingJob execute 任务方法触发成功");
        // 当前分片数,从0开始,即执行器的序号
        int shardIndex = XxlJobHelper.getShardIndex();
        //总分片数,执行器集群总机器数量
        int shardTotal = XxlJobHelper.getShardTotal();
        // 业务逻辑
        List<Integer> allUserIds = getAllUserIds();
        allUserIds.forEach(obj -> {
            if (obj % shardTotal == shardIndex) {
                log.info("第 {} 片, 命中分片开始处理用户id={}",shardIndex,obj);
            }
        });
    }
    private List<Integer> getAllUserIds() {
        List<Integer> ids = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            ids.add(i);
        }
        return ids;
    }
}

4ef55360501a4cdfa752ec50063f067a.jpg

ff532b4934ff4336b7e8566d7e930799.jpg

相关实践学习
基于MSE实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
相关文章
|
6月前
|
Java 调度 Maven
Elastic-job分布式调度系统
Elastic-job分布式调度系统
|
6月前
|
Java 调度 Maven
【分布式任务调度平台 XXL-JOB 急速入门】从零开始将 XXL-JOB 接入到自己的项目(下)
【分布式任务调度平台 XXL-JOB 急速入门】从零开始将 XXL-JOB 接入到自己的项目(下)
335 0
|
3月前
|
资源调度 Java 调度
Spring Cloud Alibaba 集成分布式定时任务调度功能
定时任务在企业应用中至关重要,常用于异步数据处理、自动化运维等场景。在单体应用中,利用Java的`java.util.Timer`或Spring的`@Scheduled`即可轻松实现。然而,进入微服务架构后,任务可能因多节点并发执行而重复。Spring Cloud Alibaba为此发布了Scheduling模块,提供轻量级、高可用的分布式定时任务解决方案,支持防重复执行、分片运行等功能,并可通过`spring-cloud-starter-alibaba-schedulerx`快速集成。用户可选择基于阿里云SchedulerX托管服务或采用本地开源方案(如ShedLock)
122 1
|
13天前
|
存储 NoSQL Java
Java调度任务如何使用分布式锁保证相同任务在一个周期里只执行一次?
【10月更文挑战第29天】Java调度任务如何使用分布式锁保证相同任务在一个周期里只执行一次?
36 1
|
2月前
|
存储 NoSQL 调度
|
6月前
|
算法 调度
电动汽车集群并网的分布式鲁棒优化调度matlab
电动汽车集群并网的分布式鲁棒优化调度matlab
|
4月前
|
资源调度 Java 调度
Spring Cloud Alibaba 集成分布式定时任务调度功能
Spring Cloud Alibaba 发布了 Scheduling 任务调度模块 [#3732]提供了一套开源、轻量级、高可用的定时任务解决方案,帮助您快速开发微服务体系下的分布式定时任务。
14933 30
|
3月前
|
机器学习/深度学习 资源调度 PyTorch
面向大规模分布式训练的资源调度与优化策略
【8月更文第15天】随着深度学习模型的复杂度不断提高,对计算资源的需求也日益增长。为了加速训练过程并降低运行成本,高效的资源调度和优化策略变得至关重要。本文将探讨在大规模分布式训练场景下如何有效地进行资源调度,并通过具体的代码示例来展示这些策略的实际应用。
379 1
|
3月前
|
Dubbo Java 调度
揭秘!Spring Cloud Alibaba的超级力量——如何轻松驾驭分布式定时任务调度?
【8月更文挑战第20天】在现代微服务架构中,Spring Cloud Alibaba通过集成分布式定时任务调度功能解决了一致性和可靠性挑战。它利用TimerX实现任务的分布式编排与调度,并通过`@SchedulerLock`确保任务不被重复执行。示例代码展示了如何配置定时任务及其分布式锁,以实现每5秒仅由一个节点执行任务,适合构建高可用的微服务系统。
67 0
|
4月前
|
消息中间件 缓存 架构师
对抗软件复杂度问题之降低代码的复杂度,如何解决
对抗软件复杂度问题之降低代码的复杂度,如何解决

热门文章

最新文章