之前一直使用的是spring task来做的定时任务(自己通过通过集成mysql、redis、zookeeper来实现的分布式、高可用的任务动态调度)后来了解到了当当开源的Elastic-Job分布式调度解决方案 记录一下
首先了解elastic-job是什么?
Elastic-Job是一个分布式调度解决方案,它是由两个相互独立的子项目Elastic-Job-Lite和Elastic-Job-Cloud组成。Elastic-Job-Lite定位为轻量级去中心化解决方案,使用jar包的形式提供分布式任务的协调服务;Job-Cloud采用自研Mesos Framework的解决方案,额外提供资源治理、应用分发以及进程隔离等功能
elastic-job如何使用
添加maven依赖
com.dangdang
elastic-job-lite-spring
2.1.5
com.dangdang
elastic-job-lite-core
2.1.5
-编写elastic的实现job类
ElasticJob下面有三个实现接口
1、SimpleJob
2、DataFlowJob 数据流job
3、ScriptJob 脚本任务
SimpleJob实现
@Component
public class FFSimpleJob implements SimpleJob {
@Override
public void execute(ShardingContext shardingContext) {
System.out.println(
"当前线程名称:"+Thread.currentThread().getName()+
",当前线程id:"+Thread.currentThread().getId()+
",分片总数:"+shardingContext.getShardingTotalCount()+
",当前分片参数:"+shardingContext.getShardingParameter()+
",当前分片"+shardingContext.getShardingItem());
}
}
@Configuration
public class FFElasticJobConfig {
@Bean(initMethod = "init")
public ZookeeperRegistryCenter registryCenter(){
//依赖zk
String host = "www.ff-coder.cn:2181";
String namespace = "elastic-job-demo";
return new ZookeeperRegistryCenter(new ZookeeperConfiguration(host,namespace));
}
@Bean(initMethod = "init")
public JobScheduler simpleJobScheduler(){
SimpleJob simpleJob = new FFSimpleJob();
String cron = "0/2 * * * * ? *";
String shardingItemParameters = "0=小明,1=小红,2=jack,3=tom";
int shardingTotalCount = 4;
// 构建job
return new SpringJobScheduler(simpleJob,registryCenter(),getLiteJobConfiguration(simpleJob.getClass(),cron,shardingItemParameters,shardingTotalCount));
}
public LiteJobConfiguration getLiteJobConfiguration(Class extends ElasticJob> jobClass, String cron, String shardingItemParameters, int shardingTotalCount){
//定义分配策略
JobCoreConfiguration jobCoreConfiguration = JobCoreConfiguration.newBuilder(jobClass.getName(), cron, shardingTotalCount).shardingItemParameters(shardingItemParameters).failover(true).build();
//定义simple类型配置
SimpleJobConfiguration simpleJobConfiguration = new SimpleJobConfiguration(jobCoreConfiguration,jobClass.getCanonicalName());
//分片策略
JobShardingStrategy jobShardingStrategy = null;
// AverageAllocationJobShardingStrategy 平均分配算法的分片策略(默认)
// 如果有3个服务器, 分成4片, 则每台服务器分到的分片是: 1=[0,3], 2=[1], 3=[2].
// 如果有3台服务器, 分成9片, 则每台服务器分到的分片是: 1=[0,1,2], 2=[3,4,5], 3=[6,7,8].
// 如果有3台服务器, 分成8片, 则每台服务器分到的分片是: 1=[0,1,6], 2=[2,3,7], 3=[4,5].
// 如果有3台服务器, 分成10片, 则每台服务器分到的分片是: 1=[0,1,2,9], 2=[3,4,5], 3=[6,7,8].
jobShardingStrategy = new AverageAllocationJobShardingStrategy();
// OdevitySortByNameJobShardingStrategy 根据作业名的哈希值奇偶数决定IP升降序算法的分片策略.
//首先 作业名的哈希值为奇数则IP升序. 作业名的哈希值为偶数则IP降序.然后再调用AverageAllocationJobShardingStrategy的平均分片算法进行分片。
jobShardingStrategy = new OdevitySortByNameJobShardingStrategy();
// RotateServerByNameJobShardingStrategy 根据作业名的哈希值对服务器列表进行轮转的分片策略.
jobShardingStrategy = new RotateServerByNameJobShardingStrategy();
//定义lite作业配置
return LiteJobConfiguration.newBuilder(simpleJobConfiguration).overwrite(true).build();
}
}
运行方法 输出
当前线程名称:inner-job-com.ff.elasticJob.config.FFSimpleJob-7,当前线程id:81,分片总数:4,当前分片参数:小明,当前分片0
当前线程名称:inner-job-com.ff.elasticJob.config.FFSimpleJob-7,当前线程id:81,分片总数:4,当前分片参数:小红,当前分片1
当前线程名称:inner-job-com.ff.elasticJob.config.FFSimpleJob-1,当前线程id:74,分片总数:4,当前分片参数:jack,当前分片2
当前线程名称:inner-job-com.ff.elasticJob.config.FFSimpleJob-7,当前线程id:81,分片总数:4,当前分片参数:tom,当前分片3
当前线程名称:inner-job-com.ff.elasticJob.config.FFSimpleJob-5,当前线程id:79,分片总数:4,当前分片参数:小明,当前分片0
当前线程名称:inner-job-com.ff.elasticJob.config.FFSimpleJob-4,当前线程id:78,分片总数:4,当前分片参数:小红,当前分片1
当前线程名称:inner-job-com.ff.elasticJob.config.FFSimpleJob-5,当前线程id:79,分片总数:4,当前分片参数:jack,当前分片2
当前线程名称:inner-job-com.ff.elasticJob.config.FFSimpleJob-4,当前线程id:78,分片总数:4,当前分片参数:tom,当前分片3
当前线程名称:inner-job-com.ff.elasticJob.config.FFSimpleJob-7,当前线程id:81,分片总数:4,当前分片参数:小明,当前分片0
当前线程名称:inner-job-com.ff.elasticJob.config.FFSimpleJob-8,当前线程id:82,分片总数:4,当前分片参数:小红,当前分片1
当前线程名称:inner-job-com.ff.elasticJob.config.FFSimpleJob-7,当前线程id:81,分片总数:4,当前分片参数:jack,当前分片2
当前线程名称:inner-job-com.ff.elasticJob.config.FFSimpleJob-8,当前线程id:82,分片总数:4,当前分片参数:tom,当前分片3
下面我们对结果进行分析
我们可以看到在运行的时候通过设置分片总数shardingTotalCount=4,我们当前在一台机器上运行,程序给我们创建了4个线程去执行,并且每个线程执行了4次。
我们现在创建一个新的进程一起执行开一下效果
image.png
image.png
image.png
停止其中一个进程
image.png
可以看到 当有两个进程的时候 进程1分别执行了0,1分片、进程3分别执行了 2,3分片 当我们把其中一个进程停止后 另一个进程会重新启动4个线程执行4个分片
在实际开发过程中如何使用
在开发过程中经常会有订单跑批等业务,现在有一个场景每天凌晨执行订单跑批的处理,而这个订单数据量非常大 需要执行几个小时,那我们可以通过订单的一些规则,设置对应的分片数,每个job中通过不同的参数(规则)执行不同的处理,这样的话一台服务器上的工作,将会分摊到多个机器上进行处理,效率将会有很大的提升
扩展
在实际开发中我们的数据量可能会有高峰期,那么就不能将分片数写死到代码中,我们得通过不同的时间段设置 分别设置分片数
elastic-job有给我们提供一套页面elastic-job-console 该项目在github下面
我们可以设置 注册中心名称,地址,及zk的命名空间
image.png
可以查询到已有的作业任务
image.png
还可以动态的修改我们的分片数,执行时间,分片参数等
image.png
遗留问题
1、elastic-job是如何分片的,多进程情况下是如何感知并动态分配的
2、elatstic-job在zk中的存储结构
3、elastic-job的故障转移是如何实现的