小项目定时任务和业务代码存放在同一个JVM,即同一个服务器;大公司定时任务执行和业务代码服务器是分开的,是独立的JVM。下面学习分布式定时任务!
传统定时任务请访问:连接
(1)传统情况下定时任务会出现哪些问题?
宕机、报错、高并发
(2)在高并发下导致Job服务器宕机,这时怎么处理?
使用心跳检测监控,自动重启;
使用补偿机制,即Job没有完成情况下要补偿执行,每个任务打一个小标记看有没有完成,没有完成要补偿机制;
(3)定时任务执行代码时候中间突然报错,这时怎么处理?
放弃执行错误部分,日志记录错误,跳过继续执行
(4)定时任务服务器是否需要考虑高并发?
需要考虑高并发,间隔场景不需要高并发,同时场景会发生高并发
底层其实就是把Quartz框架进行包装,实现分布式Job
①使用zookeeper实现分布式锁——缺点是要创建临时节点和事件通知,不易于扩展
②使用配置文件做一个开关——缺点是发布后,需要重启
③数据库唯一约束——缺点是效率低
④使用分布式任务调度平台XXL-JOB、Elastric-Job(依赖ZK)、TBSchedule
XXL-JOB 的GitHub地址:https://github.com/xuxueli/xxl-job
开发文档:连接
主要特点:线程池多线程触发、邮件报警、状态监控、失败处理、子任务依赖、执行日志
下面是官网的一些特点:
(1)简单: 一分钟上手。支持通过Web页面(有一个专门的页面)对任务进行CRUD操作;
(2)动态: 支持动态修改任务状态、暂停/恢复任务,以及终止运行中任务,即时生效;
(3)调度中心HA(中心式):调度采用中心式设计,“调度中心”基于集群Quartz实现;
(4)任务Failover: 执行器集群部署时,任务路由策略选择"故障转移"情况下调度失败时将会平滑切换执行器进行Failover;
(5)一致性: “调度中心”通过数据库锁保证集群分布式调度的一致性, 一次任务调度只会触发一次执行;
(6)自定义任务参数: 支持在线配置调度任务入参,即时生效;
(7)调度线程池: 调度系统多线程触发调度运行;
(8)弹性扩容缩容: 一旦有新执行器机器上线或者下线,下次调度时将会重新分配任务;
(9)邮件报警: 任务失败时支持邮件报警,支持配置多邮件地址群发报警邮件;
(10)状态监控: 支持实时监控任务进度;
(11)执行日志: 支持在线查看调度结果,并且支持以Rolling方式实时查看执行器输出的完整的执行日志;
(12)数据加密: 调度中心和执行器之间的通讯进行数据加密,提升调度信息安全性;
(13)任务依赖: 支持配置子任务依赖,当父任务执行结束且执行成功后将会主动触发一次子任务的执行, 多个子任务用逗号分隔;
(14)推送maven中央仓库: 将会把最新稳定版推送到maven中央仓库, 方便用户接入和使用;
(15)任务注册: 执行器会周期性自动注册任务, 调度中心将会自动发现注册的任务并触发执行。同时,也支持手动录入执行器地址;
(16)路由策略: 执行器集群部署时提供丰富的路由策略,包括:第一个、最后一个、轮询、随机、一致性HASH、最不经常使用、最近最久未使用、故障转移、忙碌转移等;
(17)运行报表: 支持实时查看运行数据,如任务数量、调度次数、执行器数量等;以及调度报表,如调度日期分布图,调度成功分布图等;
(18)脚本任务: 支持以GLUE模式开发和运行脚本任务,包括Shell、Python等类型脚本;
(19)阻塞处理策略: 调度过于密集执行器来不及处理时的处理策略,策略包括:单机串行(默认)、丢弃后续调度、覆盖之前调度;
(20)失败处理策略; 调度失败时的处理策略,策略包括:失败告警(默认)、失败重试;
(21)分片广播任务: 执行器集群部署时,任务路由策略选择"分片广播"情况下,一次任务调度将会广播触发对应集群中所有执行器执行一次任务,同时传递分片参数;可根据分片参数开发分片任务;
(22)动态分片: 分片广播任务以执行器为维度进行分片,支持动态扩容执行器集群从而动态增加分片数量,协同进行业务处理;在进行大数据 量业务操作时可显著提升任务处理能力和速度;
(23)事件触发: 除了"Cron方式"和"任务依赖方式"触发任务执行之外,支持基于事件的触发任务方式。调度中心提供触发任务单次执行的API服务,可根据业务事件灵活触发。
(24)支持Job集群
(25)动态配置定时规则(传统定时规则都是写死的)
略,可到gitHub找
# web port
server.port=8081
# 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 executor address
xxl.job.executor.appname=app-itmayiedu
xxl.job.executor.ip=
xxl.job.executor.port=9999
### xxl-job, access token
xxl.job.accessToken=
### xxl-job log path
xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
### xxl-job log retention days
xxl.job.executor.logretentiondays=-1
@Configuration
@ComponentScan(basePackages = "com.xxl.job.executor.service.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(initMethod = "start", destroyMethod = "destroy")
public XxlJobExecutor xxlJobExecutor() {
logger.info(">>>>>>>>>>> xxl-job config init.");
XxlJobExecutor xxlJobExecutor = new XxlJobExecutor();
xxlJobExecutor.setAdminAddresses(adminAddresses);
xxlJobExecutor.setAppName(appName);
xxlJobExecutor.setIp(ip);
xxlJobExecutor.setPort(port);
xxlJobExecutor.setAccessToken(accessToken);
xxlJobExecutor.setLogPath(logPath);
xxlJobExecutor.setLogRetentionDays(logRetentionDays);
return xxlJobExecutor;
}
}
//只要类上加@JobHandler都会注册到XXL-Job执行器容器中
@JobHandler("demoJobHandler")
@Component
public class DemoHandler extends IJobHandler {
@Value("${server.port}")
private String serverPort;
@Override
public ReturnT execute(String param) throws Exception {
System.out.println("######端口号:serverPort" + serverPort + "###定时Job开始执行啦!!!!######");
return SUCCESS;
}
}
略