xxl-job实践,集群
起因最近公司准备使用xxl-job,让本人调研一下,以下是调研一下午的成果,记录一下分布式任务调度调研(建议跳过)开源方案elastic-job:Elastic-Job是一个分布式调度解决方案,由两个相互独立的子项目Elastic-Job-Lite和Elastic-Job-Cloud组成。Elastic-Job-Lite定位为轻量级无中心化解决方案,使用jar包的形式提供分布式任务的协调服务。El
起因
最近公司准备使用xxl-job,让本人调研一下,以下是调研一下午的成果,记录一下
分布式任务调度调研(建议跳过)
开源方案
-
elastic-job:Elastic-Job是一个分布式调度解决方案,由两个相互独立的子项目Elastic-Job-Lite和Elastic-Job-Cloud组成。
Elastic-Job-Lite定位为轻量级无中心化解决方案,使用jar包的形式提供分布式任务的协调服务。
Elastic-Job-Cloud使用Mesos + Docker的解决方案,额外提供资源治理、应用分发以及进程隔离等服务。
可惜的是已经两年没有迭代更新记录。
-
xxl-job:一个轻量级分布式任务调度平台,主打特点是平台化,易部署,开发迅速、学习简单、轻量级、易扩展,代码仍在持续更新中。
“调度中心”是任务调度控制台,平台自身并不承担业务逻辑,只是负责任务的统一管理和调度执行,并且提供任务管理平台, “执行器” 负责接收“调度中心”的调度并执行,可直接部署执行器,也可以将执行器集成到现有业务项目中。 通过将任务的调度控制和任务的执行解耦,业务使用只需要关注业务逻辑的开发。
主要提供了任务的动态配置管理、任务监控和统计报表以及调度日志几大功能模块,支持多种运行模式和路由策略,可基于对应执行器机器集群数量进行简单分片数据处理。
-
quartz:是Java领域最著名的开源任务调度工具,也是目前事实上的定时任务标准,几乎全部的开源定时任务框架都是基于Quartz核心调度构建而成。
缺点:
(1)需要把任务信息持久化到业务数据表,和业务有耦合。
(2)调度逻辑和执行逻辑并存于同一个项目中,在机器性能固定的情况下,业务和调度之间不可避免地会相互影响。
(3)quartz集群模式下,是通过数据库独占锁来唯一获取任务,任务执行并没有实现完善的负载均衡机制。
-
TBSchedule:阿里早期开源的分布式任务调度系统。代码略陈旧,使用的是Timer而不是线程池执行任务调度。TBSchedule的作业类型比较单一,只能是获取/处理数据一种模式,文档缺失比较严重。
-
Saturn:唯品会开源的一个分布式任务调度平台,在Elastic Job的基础上进行了改造。
-
CronMan:
技术选型
XXL-JOB:
- 轻量级,支持通过Web页面对任务进行动态CRUD操作,操作简单
- 只依赖数据库作为集群注册中心,接入开发简单,不需要ZK
- 高可用、解耦、高性能、监控报警、分片、重试、故障转移
- 团队持续开发,社区活跃
- 支持后台直接查看每个任务执行实时日志,ELASTIC-JOB中应该是没有这个功能
具体实现
先从git或者gitee上clone下项目
1、配置nginx
2、配置db
运行项目中:doc-db-sql脚本
3、配置xxl-job调度中心
修改admin模块配置:
去掉server.servlet.context-path这行
将admin工程打成jar,上传到服务器,运行
nohup java -jar xxl-job-admin-2.3.0.jar &
4、项目中集成xxl-job执行器(也可单独部署执行器,并使用rpc调用任务)
导入依赖:
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>2.3.0</version>
</dependency>
配置执行器:注意server.port 和 xxl.job.admin.addresses 和 xxl.job.executor.appname 和 xxl.job.executor.port
# web port
server.port=8082
# 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://192.168.216.133:8080/xxl-job-admin/
### xxl-job, access token
xxl.job.accessToken=
### xxl-job executor appname
xxl.job.executor.appname=test-executor
### 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=
xxl.job.executor.port=9999
### 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
编写config类(clone下来的项目中此处有坑,应该是作者没改,需将@Bean后括号中内容删掉,不然启动报错):
package cn.xqh.xxljobtest.jobhandler.config;
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.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* @author: qihang.xu
* @date: 2021/12/15 17:03
* @desc: TODO
*/
@Configuration
@ComponentScan(basePackages = "cn.xqh.xxljobtest.jobhandler")
public class XxlJobConfig {
private Logger logger = 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;
@Bean
public XxlJobSpringExecutor xxlJobExecutor() {
logger.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 ;
}
}
编写handler:
package cn.xqh.xxljobtest.jobhandler;
import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.handler.annotation.XxlJob;
import org.springframework.stereotype.Component;
/**
* @author: qihang.xu
* @date: 2021/12/15 16:57
* @desc: TODO
*/
@Component
public class TestJobHandler extends IJobHandler {
@Override
@XxlJob(value = "AJobHandler")
public void execute() throws Exception {
System.out.println("定时任务执行");
}
}
5、调度中心配置执行器和执行任务
调度中心->执行器管理->新增,名称和你执行器配置的名称相同
调度中心->任务管理->新增
6、项目定时任务迁移测试:执行成功!
高可用实践
1、执行器高可用
在项目中做完上面第4步后,打包项目,修改执行器端口,再次打包项目;发布项目,现在就有了两个除执行器配置不同,其余逻辑都相同的jar,部署jar,在调度中心-执行器管理中,可以看到执行器集群:
再在任务管理中配置执行器策略:轮询、故障转移等;
验证:启动任务后,停掉一个执行器服务,可以看到任务继续执行。懒得截图
2、调度中心高可用
单机:修改调度中心端口号,重新打包
非单机:直接打包
发布项目
通过nginx做负载均衡
配置完成
验证:访问服务器ip,可以跳到监控页面,停掉一个调度中心,访问页面正常。懒得截图ovo
遗留的问题
- 在项目中集成执行器过于僵硬,将来升级的方向可以将执行器单独部署,在handler中通过rpc执行任务
- nginx负载均衡,upstream中只能代理到端口,如果想在端口后继续增加路径,则报无法识别的错误,暂时未找到解决方案,只能去掉“server.servlet.context-path=”参数。(可能是本人nginx玩的不6,毕竟这是运维的事儿,能用就行,能用就行~)
更多推荐
所有评论(0)