读取目录
xxl-job部署
xxl-job 两种部署方式:
一种是基于docker 一种是本地jar包部署 但两种部署都要有数据库
使用xxl-job需要建表
springboot引入依赖
添加配置
@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;
}
然后再xxl job admin 中设置
首先新增执行器,一般一个微服务就一个执行器,这个appname需要与你配置里面的executor下的appname一致
然后选择任务管理,选择执行器,然后新增任务
然后在执行器中新增任务,重点jobhandler与代码中注解一致即可
天机学堂中的配置:
nacos配置文件中的配置:
tj:
xxl-job:
access-token: tianji
admin:
address: http://192.168.150.101:8880/xxl-job-admin
executor:
appname: ${spring.application.name}
log-retention-days: 10
logPath: job/${spring.application.name}
读取配置中的属性
@Data
@ConfigurationProperties(prefix = "tj.xxl-job")
public class XxlJobProperties {
private String accessToken;
private Admin admin;
private Executor executor;
@Data
public static class Admin {
private String address;
}
@Data
public static class Executor {
private String appName;
private String address;
private String ip;
private Integer port;
private String logPath;
private Integer logRetentionDays;
}
}
注入到config配置中
@Slf4j
@Configuration
@ConditionalOnClass(XxlJobSpringExecutor.class)
@EnableConfigurationProperties(XxlJobProperties.class)
public class XxlJobConfig {
@Bean
public XxlJobSpringExecutor xxlJobExecutor(XxlJobProperties prop) {
log.info(">>>>>>>>>>> xxl-job config init.");
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
XxlJobProperties.Admin admin = prop.getAdmin();
if (admin != null && StringUtils.isNotEmpty(admin.getAddress())) {
xxlJobSpringExecutor.setAdminAddresses(admin.getAddress());
}
XxlJobProperties.Executor executor = prop.getExecutor();
if (executor != null) {
if (executor.getAppName() != null)
xxlJobSpringExecutor.setAppname(executor.getAppName());
if (executor.getIp() != null)
xxlJobSpringExecutor.setIp(executor.getIp());
if (executor.getPort() != null)
xxlJobSpringExecutor.setPort(executor.getPort());
if (executor.getLogPath() != null)
xxlJobSpringExecutor.setLogPath(executor.getLogPath());
if (executor.getLogRetentionDays() != null)
xxlJobSpringExecutor.setLogRetentionDays(executor.getLogRetentionDays());
}
if (prop.getAccessToken() != null)
xxlJobSpringExecutor.setAccessToken(prop.getAccessToken());
log.info(">>>>>>>>>>> xxl-job config end.");
return xxlJobSpringExecutor;
}
}
执行器的名称要一致
选择队形的执行器,添加任务
任务调度jobhandler与@xxljob一致
分片广播
当数据有很多的时候一台服务器处理起来可能需要很长时间,此时我们可以通过横向拓展增加服务器的方式来加快处理速度,但是对于一个定时任务来说,两个服务代码都是一样的,会造成重复执行,这就用到分片了,两台服务分别处理不同的数据
因此,将来肯定会将学习服务多实例部署,这样就会有多个执行器并行执行。但是,如果交给多个任务执行器,大家执行相同代码,都从第1页逐页处理数据,又会出现重复处理的情况。
怎么办?
这就要用到任务分片的方案了。
要想知道每一个执行器执行哪些页数据,只要弄清楚两个关键参数即可:
-
起始页码:pageNo
-
下一页的跨度:step
而这两个参数是有规律的:
-
起始页码:执行器编号(从0开始)是多少,起始页码就是多少
-
页跨度:执行器有几个,跨度就是多少。也就是说你要跳过别人读取过的页码
因此,现在的关键就是获取两个数据:
-
执行器编号(执行器开始执行时,每一个执行器都有一个编号,从0开始依次递增)
-
执行器总数量
-
可通过下面两行代码获取编号和总数量
获取到编号和总数量之后,然后进行翻页处理数据,就可以不重复处理了
任务链
也可能是我们逻辑有问题(可能也不是bug)
可以看到每一个任务都有任务id,在某一个任务页面板上有个 子任务ID ,当前任务执行完之后就会执行子任务ID,但是存在bug,当分片广播执行时,有个微服务把他这个分片的任务执行完了,他不会等待其他分片是否执行,直接执行他的子任务。(在读取缓存到数据库时,一个分片执行完了,然后子任务是清除缓存,别的任务没执行完,清理完缓存后得不到数据了)