任务调度是日常开发中非常常见的一个业务场景,我们经常需要去运行一些的周期性、指定时间点等方式自动触发的异步业务逻辑。
问题:
分布式集群的模式下,如果采用集中式的任务调度方式,会带来一些问题,比如:
1、多台机器集群部署的定时任务如何保证不被重复执行?
2、如何动态地调整定时任务的执行时间?(不重启服务的情况)
3、部署定时任务的机器发生故障如何实现故障转移?
4、如何对定时任务进行监控?
5、业务量比较大,单机性能的瓶颈问题,如何扩展?
等等问题
解决方案:
1、数据库唯一约束,避免定时任务重复执行(类似于分布式锁,插入成功执行,否则不执行);
2、使用配置文件:redis、mysql作为调度的开关(存入执行机器的ip);
3、使用分布式锁实现调度的控制;
4、使用分布式任务调度平台TBSchedule(淘宝)、Elastic-Job(当当)、Saturn(唯品会)、XXL-JOB(大众点评)、 Google Cron(谷歌)系统;
5、自研
1、不支持分片任务
处理有序数据时,多机器分片执行任务处理不同数据
2、不支持生命周期统一管理
不重启服务情况下关闭、启动任务。
3、不支持集群
存在任务重复执行的问题
4、不支持失败重试
出现异常后任务终结,不能根据执行状态控制任务重新执行
5、不支持动态调整
不重启服务的情况下修改任务参数
6、无报警机制
任务失败之后没有报警机制
7、任务数据统计难以统计
任务数据量大时,对于任务执行情况无法高效的统计执行情况
1、调用API的的方式操作任务,不人性化 ;
2、需要持久化业务QuartzJobBean到底层数据表中,系统侵入性相当严重。
3、调度逻辑和QuartzJobBean耦合在同一个项目中,这将导致一个问题,在调度任务数量逐渐增多,同时调度任务逻辑逐渐加重的情况加,此时调度系统的性能将大大受限于业务;
4、quartz底层以“抢占式”获取DB锁并由抢占成功节点负责运行任务,会导致节点负载悬殊非常大;而XXL-JOB通过执行器实现“协同分配式”运行任务,充分发挥集群优势,负载各节点均衡。
XXL-JOB弥补了quartz的上述不足之处。
美团开源的一个轻量级分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,例如:京东,优信二手车,北京尚德,360金融 (360),联想集团 (联想),易信 (网易)等等。
官网:http://www.xuxueli.com/xxl-job
Github:https://github.com/xuxueli/xxl-job
服务端(调度中心):就是一个web管理后台
客户端(执行器):就是我们写的代码,这个代码里面执行定时任务的业务逻辑
心跳机制:
RPC:
1、客户端client发起服务调用请求。
2、client stub 可以理解成一个代理,会将调用方法、参数按照一定格式进行封装,通过服务提供的地址,发起网络请求。
3、消息通过网络传输到服务端。
4、server stub接受来自socket的消息。
5、server stub将消息进行解包、告诉服务端调用的哪个服务,参数是什么。
6、结果返回给server stub。
7、sever stub把结果进行打包交给socket
8、socket通过网络传输消息。
9、client stub 从socket拿到消息。
10、client stub解包消息将结果返回给client。
1、【新增】调度过期策略:调度中心错过调度时间的补偿处理策略,包括:忽略、立即补偿触发一次等;
2、【新增】触发策略:除了常规Cron、API、父子任务触发方式外,新增提供 “固定间隔触发、(固定延时触发,实验中)” 新触发方式;
3、【新增】新增任务辅助工具 “XxlJobHelper”:提供统一任务辅助能力,包括:任务上下文信息维护获取(任务参数、任务ID、分片参数)、日志输出、任务结果设置……等;
3.1、“ShardingUtil” 组件废弃:改用 “XxlJobHelper.getShardIndex()/getShardTotal();” 获取分片参数;
3.2、“XxlJobLogger” 组件废弃:改用 “XxlJobHelper.log” 进行日志输出;
4、执行器注册组件优化:注册逻辑调整为异步方式,提高注册性能;
5、任务核心类 “IJobHandler” 的 “execute” 方法取消出入参设计。改为通过 “XxlJobHelper.getJobParam” 获取任务参数并替代方法入参,通过 “XxlJobHelper.handleSuccess/handleFail” 设置任务结果并替代方法出参,示例代码如下:
@XxlJob("demoJobHandler")
public void execute() {
String param = XxlJobHelper.getJobParam(); // 获取参数
XxlJobHelper.handleSuccess(); // 设置任务结果
}
6、任务调度生命周期重构:调度(schedule)、触发(trigger)、执行(handle)、回调(callback)、结束(complete);等等
流程:
1、从github(https://github.com/xuxueli/xxl-job)获取项目源码;
2、从源码中得到SQL脚本创建和初始化数据库;
3、修改admin配置文件;
4、配置执行器
在1号位置处配置修改:
2号位置处是执行器示例
5、运行项目访问:http://localhost:8080/xxl-job-admin/toLogin
用户名:admin
密码:123456
6、运行报表
7、执行器注册
8、任务配置
1、pom添加依赖
<dependency>
<groupId>com.xuxueligroupId>
<artifactId>xxl-job-coreartifactId>
<version>2.3.0version>
dependency>
2、打包admin
3、移植config配置
4、测试执行器
移入项目成功
1、
发生此问题是因为JDK版本过高,降低为1.8即可,但并不会影响使用
2、检查pom是否有以下依赖若没有运行会报错,请添加
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
集群
xxl-job-admin如果想实现Job集群需要实现:
建议:推荐通过Nginx为调度中心集群做负载均衡,分配域名。调度中心访问、执行器回收配置、调用API服务等操作均通过该域名进行。
host文件配置
127.0.0.1 xxljob.mayikt.com
nginx配置
http {
include mime.types;
default_type application/octet-stream;
upstream backserver {
server 127.0.0.1:8080 weight=1;
server 127.0.0.1:8081 weight=1;
}
server {
listen 80;
server_name xxljob.mayikt.com;
location / {
proxy_pass http://backserver;
index index.html index.htm;
}
}
}
xxl-job执行器配置文件
xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin,http://127.0.0.1:8081/xxl-job-admin
xxl-job-admin,启动两个节点,端口分别为8080和8081
访问:http://xxljob.mayikt.com/xxl-job-admin
此时调度中心8080节点为主主节点,8081为从节点、
使用
浏览器访问nginx地址,转发到8080或8081 xxl-job-admin管理平台。
停掉8080主节点,此时调度中心到了8081备节点执行了。