Elastic-Job是当当开源的分布式弹性作业框架。Elastic-Job分为lite和cloud两个相对独立的版本,lite版为轻量级去中心化的版本,cloud版则是基于Mesos + Docker方案提供了资源治理、应用分发和服务隔离的功能。我们项目使用的是lite版的Elastic-Job,因此本文主要围绕lite版本进行介绍。
elastic-job-lite主要的设计理念是无中心化的分布式定时调度框架,思路来源于Quartz的基于数据库的高可用方案。但数据库没有分布式协调功能,所以在高可用方案的基础上增加了弹性扩容和数据分片的思路,以便于更大限度的利用分布式服务器的资源。
任务的分布式执行,需要将一个任务拆分为多个独立的任务项,然后由分布式的服务器分别执行某一个或几个分片项。
例如:有一个遍历数据库某张表的作业,现有2台服务器。
为了快速的执行作业,那么每台服务器应执行作业的50%。 为满足此需求,可将作业分成2片,每台服务器执行1片。
作业遍历数据的逻辑可以为:服务器A遍历ID以奇数结尾的数据;服务器B遍历ID以偶数结尾的数据。
如果分成10片,则服务器A被分配到分片项0,1,2,3,4;服务器B被分配到分片项5,6,7,8,9。
作业遍历数据的逻辑可以为:服务器A遍历ID以0-4结尾的数据;服务器B遍历ID以5-9结尾的数据。
Elastic-Job并不直接提供数据处理的功能,框架只会将分片项分配至各个运行中的作业服务器,开发者需要自行处理分片项与真实数据的对应关系。以上面例子分成10片为例,框架只负责决定服务器分配到哪些分片项,由作业分配策略决定,但是每个分片处理哪一部分数据,比如第一个分片处理id以0-4结尾的数据,是由开发者去决定和处理的。
elastic-job-lite是去中心化设计,作业调度中心节点,各个作业节点是自治的,作业框架的程序在到达相应时间点时各自触发调度,缺点是可能会存在各个作业服务器的时间不一致的问题。
官方的版本可以通过两种方式进行作业开发:
具体可以参看官方文档——快速入门、官方文档——开发指南。
由于我们的项目采用的是springboot框架,因此个人在官方代码的基础上做了一层封装,增加通过注解配置任务、sleuth组件支持,具体见:elastic-job-spring-boot-starter。
Elastic-Job提供Simple、Dataflow和Script 3种作业类型。 方法参数shardingContext包含作业配置、片和运行时信息。可通过getShardingTotalCount(), getShardingItem()等方法分别获取分片总数,运行在本作业服务器的分片序列号等。
意为简单实现,未经任何封装的类型。需实现SimpleJob接口。该接口仅提供单一方法用于覆盖,此方法将定时执行。与Quartz原生接口相似,但提供了弹性扩缩容和分片等功能。
public class MyElasticJob implements SimpleJob {
@Override
public void execute(ShardingContext context) {
switch (context.getShardingItem()) {
case 0:
// do something by sharding item 0
break;
case 1:
// do something by sharding item 1
break;
case 2:
// do something by sharding item 2
break;
// case n: ...
}
}
}
Dataflow类型用于处理数据流,需实现DataflowJob接口。该接口提供2个方法可供覆盖,分别用于抓取(fetchData)和处理(processData)数据。
public class MyElasticJob implements DataflowJob {
@Override
public List fetchData(ShardingContext context) {
switch (context.getShardingItem()) {
case 0:
List data = // get data from database by sharding item 0
return data;
case 1:
List data = // get data from database by sharding item 1
return data;
case 2:
List data = // get data from database by sharding item 2
return data;
// case n: ...
}
}
@Override
public void processData(ShardingContext shardingContext, List data) {
// process data
// ...
}
}
流式处理
可通过DataflowJobConfiguration配置是否流式处理。
流式处理数据只有fetchData方法的返回值为null或集合长度为空时,作业才停止抓取,否则作业将一直运行下去; 非流式处理数据则只会在每次作业执行过程中执行一次fetchData方法和processData方法,随即完成本次作业。
如果采用流式作业处理方式,建议processData处理数据后更新其状态,避免fetchData再次抓取到,从而使得作业永不停止。 流式数据处理参照TbSchedule设计,适用于不间歇的数据处理。
Script类型作业意为脚本类型作业,支持shell,python,perl等所有类型脚本。只需通过控制台或代码配置scriptCommandLine即可,无需编码。执行脚本路径可包含参数,参数传递完毕后,作业框架会自动追加最后一个参数为作业运行时信息。
#!/bin/bash
echo sharding execution context is $*
作业运行时输出
sharding execution context is {“jobName”:“scriptElasticDemoJob”,“shardingTotalCount”:10,“jobParameter”:“”,“shardingItem”:0,“shardingParameter”:“A”}
Elastic-Job配置分为3个层级,分别是Core, Type和Root。每个层级使用相似于装饰者模式的方式装配。
Core对应JobCoreConfiguration,用于提供作业核心配置信息,如:作业名称、分片总数、CRON表达式等。
Type对应JobTypeConfiguration,有3个子类分别对应SIMPLE, DATAFLOW和SCRIPT类型作业,提供3种作业需要的不同配置,如:DATAFLOW类型是否流式处理或SCRIPT类型的命令行等。
Root对应JobRootConfiguration,有2个子类分别对应Lite和Cloud部署类型,提供不同部署类型所需的配置,如:Lite类型的是否需要覆盖本地配置或Cloud占用CPU或Memory数量等。
通用作业配置
// 定义作业核心配置
JobCoreConfiguration simpleCoreConfig = JobCoreConfiguration.newBuilder("demoSimpleJob", "0/15 * * * * ?", 10).build();
// 定义SIMPLE类型配置
SimpleJobConfiguration simpleJobConfig = new SimpleJobConfiguration(simpleCoreConfig, SimpleDemoJob.class.getCanonicalName());
// 定义Lite作业根配置
JobRootConfiguration simpleJobRootConfig = LiteJobConfiguration.newBuilder(simpleJobConfig).build();
// 定义作业核心配置
JobCoreConfiguration dataflowCoreConfig = JobCoreConfiguration.newBuilder("demoDataflowJob", "0/30 * * * * ?", 10).build();
// 定义DATAFLOW类型配置
DataflowJobConfiguration dataflowJobConfig = new DataflowJobConfiguration(dataflowCoreConfig, DataflowDemoJob.class.getCanonicalName(), true);
// 定义Lite作业根配置
JobRootConfiguration dataflowJobRootConfig = LiteJobConfiguration.newBuilder(dataflowJobConfig).build();
// 定义作业核心配置配置
JobCoreConfiguration scriptCoreConfig = JobCoreConfiguration.newBuilder("demoScriptJob", "0/45 * * * * ?", 10).build();
// 定义SCRIPT类型配置
ScriptJobConfiguration scriptJobConfig = new ScriptJobConfiguration(scriptCoreConfig, "test.sh");
// 定义Lite作业根配置
JobRootConfiguration scriptJobRootConfig = LiteJobConfiguration.newBuilder(scriptCoreConfig).build();
与Spring容器配合使用作业,可将作业Bean配置为Spring Bean,并在作业中通过依赖注入使用Spring容器管理的数据源等对象。可用placeholder占位符从属性文件中取值。Lite可考虑使用Spring命名空间方式简化配置。
配置项详细说明请参见配置手册
public class JobDemo {
public static void main(String[] args) {
new JobScheduler(createRegistryCenter(), createJobConfiguration()).init();
}
private static CoordinatorRegistryCenter createRegistryCenter() {
CoordinatorRegistryCenter regCenter = new ZookeeperRegistryCenter(new ZookeeperConfiguration("zk_host:2181", "elastic-job-demo"));
regCenter.init();
return regCenter;
}
private static LiteJobConfiguration createJobConfiguration() {
// 创建作业配置
...
}
}
将配置Spring命名空间的xml通过Spring启动,作业将自动加载。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FsenYazD-1586316152446)(file:///C:/Users/zuhiz/AppData/Local/Packages/oice_16_974fa576_32c1d314_209e/AC/Temp/msohtmlclip1/01/clip_image001.jpg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uIDKppXc-1586316152447)(file:///C:/Users/zuhiz/AppData/Local/Packages/oice_16_974fa576_32c1d314_209e/AC/Temp/msohtmlclip1/01/clip_image003.jpg)]
IP
排序,保证分片结果不会产生较大波动(默认分片策略)。支持功能:
· 登录安全控制
· 注册中心、事件追踪数据源管理
· 快捷修改作业设置
· 作业和服务器维度状态查看
· 操作作业禁用\启用、停止和删除等生命周期
· 事件追踪查询
具体见elastic-job-lite-console。
Elastic-Job提供了事件追踪功能,可通过事件订阅的方式处理调度过程的重要事件,用于查询、统计和监控。Elastic-Job目前提供了基于关系型数据库两种事件订阅方式记录事件。
在配置作业关联数据源后,elastic-job会自动在数据库里创建JOB_EXECUTION_LOG和JOB_STATUS_TRACE_LOG两张表以及若干索引。
JOB_EXECUTION_LOG:记录每次作业的执行历史。分为两个步骤:
\1. 作业开始执行时向数据库插入数据,除failure_cause和complete_time外的其他字段均不为空。
\2. 作业完成执行时向数据库更新数据,更新is_success, complete_time和failure_cause(如果作业执行失败)。
JOB_STATUS_TRACE_LOG:记录作业状态变更痕迹表。可通过每次作业运行的task_id查询作业状态变化的生命周期和运行轨迹。
——官方版本并不支持oracle,elastic-job-spring-boot-starter中已支持。
可通过配置多个任务监听器,在任务执行前和执行后执行监听的方法。监听器分为每台作业节点均执行和分布式场景中仅单一节点执行2种。
· 分布式场景中仅单一节点执行的监听:若作业处理数据库数据,处理完成后只需一个节点完成数据清理任务即可。此类型任务处理复杂,需同步分布式环境下作业的状态同步,提供了超时设置来避免作业不同步导致的死锁,请谨慎使用。
Elastic-job 介绍与使用
Elastic-job使用及原理
Elastic-Job官方文档
一个节点完成数据清理任务即可。此类型任务处理复杂,需同步分布式环境下作业的状态同步,提供了超时设置来避免作业不同步导致的死锁,请谨慎使用。
Elastic-job 介绍与使用
Elastic-job使用及原理
Elastic-Job官方文档