- 定时任务业务逻辑代码和非定时业务逻辑代码放入在同一个jar中,如果是定时任务代码导致整个服务器崩毁,也会导致非定时业务逻辑代码崩溃。
- 如果定时任务和非定时任务业务逻辑放入在同一个jar中,集群的时候可能会造成定时任务重复执行。
如何在集群中,保证我们的定时任务只会触发一次?
- 将业务逻辑和定时任务逻辑完全分开部署,只对业务逻辑实现集群,不对我们的定时任务逻辑集群;
- 对我们Jar包加上一个开关,项目启动的时候读取该开关 如果为true的情况下则加载定时任务类,否则情况下就不加载该定时任务类;
- 在数据库加上一个主键能够创建成功,则触发定时任务,否则就不触发定时任务;
- 分布式锁,只要jar能够拿到分布式锁就能够执行定时任务,否则情况下不执行;
- 采用分布式任务调度框架。
传统定时任务的实现方案?
多线程形式、timetask(javautil包里面的工具类)、线程池(可定时得线程池)、springboot注解形式、quartz框架
- 手动的将定时任务的项目(执行器)服务器ip和端口号统一存放到我们分布式任务调度中心
- 所有的定时任务触发规则,先在我们的“分布式任务调度中心”先触发,在查询注册中心执行器集群地址,采用负载均衡的算法只会取一个地址。
- 获取该地址之后,在使用rpc远程调用调用该接口,通知他可以去触发我们的定时任务。
总结:将定时任务项目(执行器)服务ip和端口号统一注册到分布式任务调度平台中,触发的所有的定时任务,先走分布式任务调度中心;分布式任务调度中心在获取执行器集群列表,采用负载均衡算法获取一个地址,采用rpc通知
搭建XXL_JOB平台官方文档:https://www.xuxueli.com/xxl-job/
源码下载地址:https://gitee.com/xuxueli0323/xxl-job
将项目下载下来之后,执行SQL脚本创建对应的数据库。参考文档:https://www.xuxueli.com/xxl-job/#%E4%BA%8C%E3%80%81%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8
启动之后访问首页:
使用步骤:
1、首先编写执行器,也就是Java类,注意:这里定时任务是单独的项目【执行器项目】(也可以和业务逻辑项目在一起),一个springboot项目。
2、引入maven文件
com.xuxueli xxl-job-core ${project.parent.version}
3、编写配置文件
# 项目启动端口t server.port=8082 ### xxl-job连接地址,多个地址用英文逗号隔开, such as "http://address" or "http://address01,http://address02" xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin ### xxl-job, access token xxl.job.accessToken=default_token ### 注入到xxl-job平台执行器的名称 xxl.job.executor.appname=xxl-job-executor-kaico ### 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
4、编写配置文件,注入bean到容器中去
@Configuration
public class XxlJobConfig {
@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() {
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;
}
}
5、在平台上先添加执行器
后台会实时显示在线的机器
6、编写定时任务代码,在定时任务项目中编写(这里是bean模式的任务模式,只需要再类的方法上添加注解@XxlJob,指定一个value值即可。)
@Component
public class Test1 {
@XxlJob("kaicoJobHandler")
public void demoJobHandler() throws Exception {
XxlJobHelper.log("XXL-JOB,你好,这里是kaico测试1");
System.out.println("开始执行:kaicoJobHandler");
for (int i = 0; i < 5; i++) {
XxlJobHelper.log("循环执行:" + i);
TimeUnit.SECONDS.sleep(2);
}
// default success
}
}
7、在调度平台添加任务
8、查看执行日志,注意:这里日志的输出是代码中:XxlJobHelper.log("XXL-JOB,你好,这里是kaico测试1");该工具类的内容。
和注解方式一致,只不过这里使用Java代码将jobHandler添加到。
GLUE模式(Java)任务以源码方式维护在调度中心,支持通过Web IDE在线更新,实时编译和生效,因此不需要指定JobHandler。相当于代码在调度中心上,但是却是在执行器项目上执行该代码。
第一步、添加一个定时任务
第二步、编写Java代码
实际效果:在执行器项目中输出了日志,说明代码在执行器项目中执行了。
总结:该模式还支持的其他语言见下图:
集群搭建:就是将定时任务项目在多个服务器上部署即可。
如何高效的定时群发消息?不管用户怎么增长,一定要在规定时间范围内发完
答:定时任务模块一定是集群,集群的目的是为了提高效率的问题,集群的需要保证幂等性的问题。
定时任务集群执行的时候,如何保证数据的幂等性问题任务调度分片集群?
答:采用分布式调度中心平台调用任务。调度平台在发rpc通知定时任务项目的时候会传递参数。
如何传递参数实现分片集群模式?
答:任务的路由策略选择分片广播,这时候执行一个定时任务的时候,这个任务的执行器集群都会执行对应的任务代码,集群中的每一个机器节点都会有一个分片序号,动态增加服务节点的时候分片序号是动态添加的。
如果执行器宕机的话,出现什么问题?
调度中心会报错,任务不会丢失,底层会把每一次丢失的任务记录下来,后面一次性补偿。



