架构师系列- 定时任务(四)- XXl-Job

本文对比了XXL-JOB和ElasticJob在轻量化、业务实现、管理复杂度、架构设计以及功能特性的差异,重点介绍了XXL-JOB的简单灵活、任务管理、高性能和高可用性,以及其独特的分片策略和阻塞处理机制。
摘要由CSDN通过智能技术生成

XXL-JOB是一个轻量级分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展,其中“XXL”是主要作者,大众点评许雪里名字的缩写

和ElasticJob的区别
相同点
  • E-Job和X-job都有普遍的用户基础和完整的技术文档,都能满足定时任务的基本功能需求
不同点
  • X-Job 侧重的业务实现的简单和管理的方便,学习成本简单,失败策略和路由策略丰富,推荐使用在“用户基数相对少,服务器数量在一定范围内”的情景下使用
  • E-Job 关注的是数据,增长了弹性扩容和数据分片的思路,以便于更大限度的利用分布式服务器的资源,可是学习成本相对高些,推荐在“数据量庞大,且部署服务器数量较多”时使用算法
  • X-Job采用了中心化思想的架构,而E-Job采用了无中心的架构
功能特性
简单灵活
  • 提供Web页面对任务进行管理,管理系统支持用户管理、权限控制;
  • 支持容器部署;
  • 支持通过通用HTTP提供跨平台任务调度;
丰富的任务管理功能
  • 支持页面对任务CRUD操作;
  • 支持在页面编写脚本任务、命令行任务、Java代码任务并执行;
  • 支持任务级联编排,父任务执行结束后触发子任务执行;
  • 支持设置任务优先级;
  • 支持设置指定任务执行节点路由策略,包括轮询、随机、广播、故障转移、忙碌转移等;
  • 支持Cron方式、任务依赖、调度中心API接口方式触发任务执行
高性能
  • 调度中心基于线程池多线程触发调度任务,快任务、慢任务基于线程池隔离调度,提供系统性能和稳定性;
  • 任务调度流程全异步化设计实现,如异步调度、异步运行、异步回调等,有效对密集调度进行流量削峰;
高可用
  • 任务调度中心、任务执行节点均 集群部署,支持动态扩展、故障转移
  • 支持任务配置路由故障转移策略,执行器节点不可用是自动转移到其他节点执行
  • 支持任务超时控制、失败重试配置
  • 支持任务处理阻塞策略:调度当任务执行节点忙碌时来不及执行任务的处理策略,包括:串行、抛弃、覆盖策略
易于监控运维
  • 支持设置任务失败邮件告警,预留接口支持短信、钉钉告警;
  • 支持实时查看任务执行运行数据统计图表、任务进度监控数据、任务完整执行日志;
整体架构设计

将调度行为抽象形成“调度中心”公共平台,而平台自身并不承担业务逻辑,“调度中心”负责发起调度请求;

将任务抽象成分散的JobHandler,交由“执行器”统一管理,“执行器”负责接收调度请求并执行对应的JobHandler中业务逻辑,因此,“调度”和“任务”两部分可以相互解耦,提高系统整体稳定性和扩展性;

调度模块(调度中心)

负责管理调度信息,按照调度配置发出调度请求,自身不承担业务代码

调度系统与任务解耦,提高了系统可用性和稳定性,同时调度系统性能不再受限于任务模块; 支持可视化、简单且动态的管理调度信息,包括任务新建,更新,删除,任务报警等,所有上述操作都会实时生效,同时支持监控调度结果以及执行日志,支持执行器Failover

功能
  1. 任务管理:对调度的任务进行触发时间等配置
  2. 日志管理:查看调度的日志情况
  3. 执行器管理:管理接入的业务模块
  4. 其它,比如用户权限配置和运行统计报表等功能
执行模块(执行器)

负责接收调度请求并执行任务逻辑。

任务模块专注于任务的执行等操作,开发和维护更加简单和高效; 接收“调度中心”的执行请求、终止请求和日志请求等

工作原理
  • 任务执行器根据配置的调度中心的地址,自动注册到调度中心
  • 达到任务触发条件,调度中心下发任务
  • 执行器基于线程池执行任务,并把执行结果放入内存队列中、把执行日志写入日志文件中
  • 执行器的回调线程消费内存队列中的执行结果,主动上报给调度中心
  • 当用户在调度中心查看任务日志,调度中心请求任务执行器,任务执行器读取任务日志文件并返回日志详情

 

部署调度中心
初始化数据库

https://gitee.com/xuxueli0323/xxl-job地址下载项目源码并解压, SQL脚本位置在

/xxl-job/doc/db/tables_xxl_job.sql

 

创建用户并授权
mysql> source /opt/tables_xxl_job.sql;
mysql> CREATE USER 'xxl'@'%' IDENTIFIED BY 'xxl';
mysql> GRANT ALL ON xxl_job.* TO 'xxl'@'%' IDENTIFIED BY 'xxl' WITH GRANT OPTION;
源码结构
解压源码,按照maven格式将源码导入IDE, 使用maven进行编译即可

xxl-job-admin:调度中心
xxl-job-core:公共依赖
xxl-job-executor-samples:执行器Sample示例(选择合适的版本执行器,可直接使用,也可以参考其并将现有项目改造成执行器)
    :xxl-job-executor-sample-springboot:Springboot版本,通过Springboot管理执行器,推荐这种方式;
    :xxl-job-executor-sample-frameless:无框架版本;
配置调度中心
调度中心项目是xxl-job-admin,作用是统计管理调度平台上面的任务,负责触发以及执行调度任务,并且提供任务管理

修改application.properties
调度中心配置内容说明,可以按需进行修改

server.port=8080
#项目访问路径
server.servlet.context-path=/xxl-job-admin
spring.datasource.url=jdbc:mysql://192.168.10.30:3306/xxl_job?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
spring.datasource.username=xxl
spring.datasource.password=xxl
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
### 报警邮箱
spring.mail.host=smtp.qq.com
spring.mail.port=25
spring.mail.username=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
### 调度中心通讯TOKEN [选填]:非空时启用;
xxl.job.accessToken=
### 调度中心国际化配置 [必填]: 默认为 "zh_CN"/中文简体, 可选范围为 "zh_CN"/中文简体, "zh_TC"/中文繁体 and "en"/英文;
xxl.job.i18n=zh_CN
## 调度线程池最大线程配置【必填】
xxl.job.triggerpool.fast.max=200
xxl.job.triggerpool.slow.max=100
### 调度中心日志表数据保存天数 [必填]:过期日志自动清理;限制大于等于7时生效,否则, 如-1,关闭自动清理功能;
xxl.job.logretentiondays=30


部署项目

可以在本地直接运行xxl-job服务,或者打包后在服务器上面运行

启动服务

运行项目后访问 http://192.168.10.30:8080/xxl-job-admin ,该地址执行器将会使用到,作为回调地,默认登录账号 admin/123456, 登录后运行界面如下图所示

 

Docker部署
创建docker-comopose.yml
version: '3'
services:
  xxl-job-admin:
    image: xuxueli/xxl-job-admin:2.3.0
    restart: always
    container_name: xxl-job-admin
    environment:
      PARAMS: '--spring.datasource.url=jdbc:mysql://192.168.10.30:3306/xxl_job?Unicode=true&characterEncoding=UTF-8 --spring.datasource.username=root --spring.datasource.password=root'
    ports:
      - 8080:8080
    volumes:
      - ./data/applogs:/data/applogs
启动服务
docker-compose up -d
部署执行器
引入依赖
在项目pom文件中引入了 “xxl-job-core” 的maven依赖;

<dependency>
    <groupId>com.xuxueli</groupId>
    <artifactId>xxl-job-core</artifactId>
    <version>2.3.0</version>
</dependency>
执行器配置文件
如调度中心集群部署存在多个地址则用逗号分隔

### 调度中心部署根地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册;
xxl.job.admin.addresses=http://192.168.10.30:8080/xxl-job-admin
### 执行器通讯TOKEN [选填]:非空时启用;
xxl.job.accessToken=
### 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册
xxl.job.executor.appname=xxl-job-executor-task
### 执行器注册 [选填]:优先使用该配置作为注册地址,为空时使用内嵌服务 ”IP:PORT“ 作为注册地址。从而更灵活的支持容器类型执行器动态IP和动态映射端口问题。
xxl.job.executor.address=
### 执行器IP [选填]:默认为空表示自动获取IP,多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯实用;地址信息用于 "执行器注册" 和 "调度中心请求并触发任务";
xxl.job.executor.ip=
### 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;
xxl.job.executor.port=9999
### 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径;
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
### 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能;
xxl.job.executor.logretentiondays=30
配置执行器
@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;
    }
}
启动执行器

本地执行器服务启动后,需要在调度中心配置执行器

注意AppName就是执行器项目配置的配置项,名称可以随意,机器地址采用自动注册就可以

 

作业详情

xxl-job支持很多种任务模式,下面我们挑几个常用的介绍下

BEAN模式

Bean模式任务,支持基于方法的开发方式,每个任务对应一个方法。

原理

每个Bean模式任务都是一个Spring的Bean类实例,它被维护在“执行器”项目的Spring容器中。

任务类需要加“@JobHandler(value=”名称”)”注解,因为“执行器”会根据该注解识别Spring容器中的任务。任务类需要继承统一接口“IJobHandler”,任务逻辑在execute方法中开发,因为“执行器”在接收到调度中心的调度请求时,将会调用“IJobHandler”的execute方法,执行任务逻辑。

编写执行器

为Job方法添加注解 "@XxlJob(value="自定义jobhandler名称", init = "JobHandler初始化方法", destroy = "JobHandler销毁方法")",注解value值对应的是调度中心新建任务的JobHandler属性的值。

@Component
public class XxlJobBeanMethodTask {

    private static final Logger logger = LoggerFactory.getLogger(XxlJobBeanMethodTask.class);

    @XxlJob("methodTask")
    public void methodTask() throws Exception {
        logger.info("methodTask定时任务启动,总分片:{},当前分片:{},参数:{}",XxlJobHelper.getShardIndex(),XxlJobHelper.getShardIndex(),XxlJobHelper.getJobParam());
        XxlJobHelper.log("XXL-METHODTASK, methodTask定时任务启动");
        //执行成功标志,默认就是执行成功
        XxlJobHelper.handleSuccess();
    }
}
新建调度任务

在任务管理,选择对应的执行器新建任务

 新增完成后,可以在列表点击执行一次或者点击启动启动定时任务

GLUE模式(Java)

任务以源代码方式维护在调度中心,支持通过Web IDE在线更新,实时编译和生效,因此不需要指定JobHandler

原理

每个 “GLUE模式(Java)” 任务的代码,实际上是“一个继承自“IJobHandler”的实现类的类代码”,“执行器”接收到“调度中心”的调度请求时,会通过Groovy类加载器加载此代码,实例化成Java对象,同时注入此代码中声明的Spring服务(请确保Glue代码中的服务和类引用在“执行器”项目中存在),然后调用该对象的execute方法,执行任务逻辑。

新建调度任务

新建一个任务,注意使用使用GLUE(JAVA)模式

 

在线编辑代码

添加任务后,选择刚刚添加的GLUE(JAVA)任务,选中指定任务后,点击该任务右侧“GLUE IDE”按钮,将会前往GLUE任务的Web IDE界面

 

在该界面支持对任务代码进行开发(也可以在IDE中开发完成后,复制粘贴到编辑中)

路由策略

路由策略属于XXLJob的高级功能,可以控制执行器执行的策略

 

准备工作

启动多台XXL执行器的服务,我们启动三台服务,并查看控制台的注册情况

 

第一个

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

查看客户端日志

我们查看客户端日志,发现服务器已经调度了第一个节点

 

 

关闭客户端

我们通过执行器的注册节点发现,第一台服务器的执行器是8089端口的服务器,我们将8089服务器给关闭,然后查看执行器日志,我们发现服务执行失败

 

容错策略

但是并不会一直报错,等一段时间控制台会将已经挂掉的节点剔除出去,第一个节点已经变成了8189就可以继续执行了

 

最后一个

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

轮询

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

随机

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

一致性HASH

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

最不经常使用

当选择该策略时,会优先选择使用频率最低的那台机器,如果其中一台机器出现故障,调度任务失败,任务不会转移(实践表明效果和轮询策略一致)

最近最久未使用

当选择该策略时,会优先选择最久未使用的机器,如果其中一台机器出现故障,调度任务失败,任务不会转移(实践表明效果和轮询策略一致)

故障转移

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

忙碌转移

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

分片广播

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

XXL的分片是根据启动的客户端进行分片,

分片参数是调度中心自动传递的,不用我们手动传递,且集群中的每个index序号是固定的,即使集群中有项目宕机,也不影响其他项目的index序号,当重启宕机项目时,它的序号还是原先的

服务启动后会自动的进行服务分片,分片会根据不同的节点进行调度

阻塞策略

调度过于密集执行器来不及处理时的处理策略

准备工作

修改代码加入延时操作模拟定时任务执行超时

 

@Component
public class XxlJobBeanMethodTask {

    private static final Logger logger = LoggerFactory.getLogger(XxlJobBeanMethodTask.class);

    @XxlJob("methodTask")
    public void methodTask() throws Exception {
        logger.info("methodTask定时任务启动,总分片:{},当前分片:{},参数:{}",XxlJobHelper.getShardTotal(),XxlJobHelper.getShardIndex(),XxlJobHelper.getJobParam());
        XxlJobHelper.log("XXL-METHODTASK, methodTask定时任务启动");
        //休眠10S模拟服务执行超时
        Thread.sleep(10000);
        //执行成功标志,默认就是执行成功
        XxlJobHelper.handleSuccess();
    }
}
单机串行

调度请求进入单机执行器后,调度请求进入FIFO队列并以串行方式运行

测试

将阻塞策略设置为单机串行,当执行的任务耗时过长,同一个任务将进入执行队列等待执行,这个时候将任务停止掉,执行器还会将队列中的任务执行完成

 但是执行器还在继续执行队列中的任务,直到所有任务执行完成

 

等一段时间后,我们发现定时任务状态都已经正常了

 

丢弃后续调度

调度请求进入单机执行器后,发现执行器存在运行的调度任务,本次请求将会被丢弃并标记为失败

测试

将阻塞策略设置为丢弃后续调度,执行器发现调度未完成则直接设置为失败

 

覆盖之前调度

调度请求进入单机执行器后,发现执行器存在运行的调度任务,将会终止运行中的调度任务并清空队列,然后运行本地调度任务

测试

将阻塞策略设置为覆盖之前调度,执行器发现有任务正在调度直接将该任务设置为失败,任何进行后续调度任务

 

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值