概述
1.1 什么是任务调度?
为了自动完成特定任务,在约定的特定时刻去执行任务
例如 : 每天晚上8点发放优惠券,每天凌晨需要统一数据
1.2 为什么需要分布式调度?
单机处理极限 : 我们使用SpringTask定时器也是可以做得到,但是单机的性能(CPU,内存,硬盘)始终有限,对于海量的数据处理会有一定的极限
高可用 : 如果单机宕机了,单点故障导致整个任务调度无法使用,所以需要保证任务的高可用性
防止重复执行 : 我们部署了多台服务器,每台服务器都有自己的一个定时任务,概率会出现重复执行任务
Elastic-Job
2.1 什么是 Elastic-Job ?
是一个开源的分布式调度框架
两个相互独立的子项目Elastic-Job-Lite和Elastic-Job-Cloud组成
两个核心模块分布式调度和分布式数据分片

2.2 Leader节点
在Elastic-Job中,每个作业都有一个Leader节点
用于协调该作业的分布式任务调度
负责分发任务,参与任务的执行
当Elastic-Job启动时,会通过分布式锁选出一个Leader节点,成为该作业的主节点,如果Leader节点出现了故障,则会重新选举出新的Leader节点
Elastic-Job通过Leader节点实现了分布式任务调度的高可用性
搭建Elastic-Job
添加Zookeeper依赖
<dependency>
<groupId>com.dangdang</groupId>
<artifactId>elastic-job-lite-core</artifactId>
<version>2.1.5</version>
</dependency>
自定义任务类实现SimpleJob接口
/**
* @author: 南瓜战士
* @create-date: 2023/3/10 12:41
* 任务类
*/
public class MyElasticJob implements SimpleJob {
/**
* 执行的定时任务
* @param shardingContext
*/
@Override
public void execute(ShardingContext shardingContext) {
System.out.println("定时任务开启: " + LocalDateTime.now());
}
}
配置类
/**
* @author: 南瓜战士
* @create-date: 2023/3/10 12:47
*/
public class App {
public static void main(String[] args) {
new JobScheduler(createRegistryCenter(), createJobConfiguration()).init();
}
/**
* 实现分布式协调的注册中心
* CoordinatorRegistryCenter 主要功能
* 1.注册任务 : 将任务信息注册到分布式协调器中
* 2.管理任务节点 : 可以实现任务的动态调度和负载均衡等功能
* 3.实现分布式锁 : 防止多个节点同时对任务进行操作导致数据的不一致性
*
* @return
*/
private static CoordinatorRegistryCenter createRegistryCenter() {
//配置zk地址,调度任务的组名
ZookeeperConfiguration zookeeperConfiguration = new ZookeeperConfiguration("localhost:2181", "elastic-job-demo");
// 会话超时时间
zookeeperConfiguration.setSessionTimeoutMilliseconds(100);
// 注册
CoordinatorRegistryCenter regCenter = new ZookeeperRegistryCenter(zookeeperConfiguration);
regCenter.init();
return regCenter;
}
/**
* 创建作业配置
* @return
*/
private static LiteJobConfiguration createJobConfiguration() {
// 定义作业核心配置
JobCoreConfiguration simpleCoreConfig = JobCoreConfiguration.newBuilder("MyElasticJob","0/3 * * * * ?",1).build();
// 定义SIMPLE类型配置
SimpleJobConfiguration simpleJobConfig = new SimpleJobConfiguration(simpleCoreConfig, MyElasticJob.class.getCanonicalName());
// 定义Lite作业根配置
LiteJobConfiguration simpleJobRootConfig = LiteJobConfiguration.newBuilder(simpleJobConfig).build();
return simpleJobRootConfig;
}
}
测试

运行单个程序,按照进行任务的调度
运行多个程序,查看是否只有一个实例进行任务调度
运行多个程序后,关闭其中一个,查看是否继续进行任务调度
Zookeeper
4.1 什么是Zookeeper?
开源的分布式协调服务框架,提供了一些基本的分布式协调功能
选举,锁,命名式服务和分布式同步
4.2 Elastic-Job为什么使用Zookeeper不使用Nacos ?
原先设计之初未考虑使用 Nacos 作为其分布式协调服务
Zookeeper 在分布式协调领域有较好的实践经验,具有稳定性高,可靠性好等优点
Zookeeper 的数据模型和 API 设计适合 Elastic-Job 的需求,可以很好地支持 Elastic-Job 的任务分片,节点注册,选举等分布式协调操作
Elastic-Job两者都可以集成使用
整合SpringBoot
添加依赖
<groupId>cn.wolfcode</groupId>
<artifactId>elastic-job-springboot</artifactId>
<version>1.0.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.dangdang</groupId>
<artifactId>elastic-job-lite-spring</artifactId>
<version>2.1.5</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
任务调度配置类
/**
* 任务调度配置类
*/
@Configuration
public class ElasticJobConfig
{
@Autowired
private MyJob job;
/**
* 创建注册中心
* @param zookeeperUrl zk连接地址
* @param groupName 唯一命名空间
* @return
*/
@Bean(initMethod = "init")
public CoordinatorRegistryCenter registryCenter(@Value("${zookeeper.url}") String zookeeperUrl,
@Value("${zookeeper.groupName}") String groupName)
{
// zk的配置,配置连接和命名空间
ZookeeperConfiguration zookeeperConfiguration = new ZookeeperConfiguration(zookeeperUrl,groupName);
// 设置zk的超时时间
zookeeperConfiguration.setSessionTimeoutMilliseconds(100);
// 创建注册中心
ZookeeperRegistryCenter zookeeperRegistryCenter = new ZookeeperRegistryCenter(zookeeperConfiguration);
return zookeeperRegistryCenter;
}
/**
* 创建作业配置
* @return
*/
private static LiteJobConfiguration createJobConfiguration(Class clazz,String cron,int shardingTotalCount) {
// // // 定义作业核心配置
JobCoreConfiguration simpleCoreConfig = JobCoreConfiguration.newBuilder(clazz.getSimpleName(),cron,shardingTotalCount).build();
// 定义SIMPLE类型配置
SimpleJobConfiguration simpleJobConfig = new SimpleJobConfiguration(simpleCoreConfig, clazz.getCanonicalName());
// 定义Lite作业根配置
LiteJobConfiguration simpleJobRootConfig = LiteJobConfiguration.newBuilder(simpleJobConfig).build();
return simpleJobRootConfig;
}
/**
* 创建一个任务调度
* @param job 作业开发
* @param rc 注册中心
* @return
*/
@Bean(initMethod = "init")
public SpringJobScheduler jobScheduler(MyJob job,CoordinatorRegistryCenter rc)
{
// 作业配置
LiteJobConfiguration jobConfiguration = createJobConfiguration(job.getClass(), "0/3 * * * * ?", 1);
// 创建任务调度
SpringJobScheduler springJobScheduler = new SpringJobScheduler(job,rc,jobConfiguration);
// 返回任务调度
return springJobScheduler;
}
}
创建自定义任务调度(上面代码已经做了),这里只是详细指出
/**
* 创建一个任务调度
* @param myJob 作业开发
* @param rc 注册中心
* @return
*/
@Bean(initMethod = "init")
public SpringJobScheduler springJobScheduler(MyJob myJob,CoordinatorRegistryCenter rc)
{
// 作业配置
LiteJobConfiguration jobConfiguration = createJobConfiguration(MyJob.class, "0/3 * * * * ?", 1);
// 创建任务调度
SpringJobScheduler springJobScheduler = new SpringJobScheduler(myJob,rc,jobConfiguration);
// 返回任务调度
return springJobScheduler;
}
分片
6.1 分片概念
指任务的分布式执行,将一个任务划分成若干份
6.2 分片的规则
按照业务进行划分
分片数量 > 机器的数量,最大限度利用资源(推荐)
6.3 Dataflow 类型
任务量很多的情况下,全部加载到内存中,内存溢出的问题
零点开始执行,还会有数据发送过来
分别用于抓取(fetchData)和处理(processData)
用于处理数据流,和SimpleJob不同,以数据流的方式执行,调用fetchData抓取数据,抓取不到才会停止工作
6.4 Dataflow 和 Simple 作业类型的选择
Simple 适合处理较小的数据集或定期执行的任务,如数据同步,数据备份等
Dataflow 是一种基于数据流的处理任务,适合处理大量数据和复杂的数据处理任务,如数据清洗,数据分析,数据流作业,通过分片将数据分成多个小批次进行处理,提高任务处理速度
6.5 分片总结
例如我们分4片,两台机器,不给分片参数,Elastic-Job会帮我们自动分片,每台机器平均分两片
每个分片一个线程,一台服务器相当于一个进程,一台服务器一个进程,分到两个分配就是两个线程执行
分多少片就启动多少个线程
