就拿一个场景来说吧,如果我们的项目是部署到多台机器上,那么某一时刻,我们的定时任务肯定每台机器上都会执行一遍,那这肯定不是我们想要的结果,我们只希望有一台机器能执行。
Elastic job是当当网架构师基于Zookepper、Quartz开发并开源的一个Java分布式定时任务。Elastic job主要的功能有支持弹性扩容,通过Zookepper集中管理和监控job,支持失效转移等,这些都是Quartz等其他定时任务无法比拟的。
官网说明:
目前Elastic job的最新版本已经由原来的elastic-job-core分离除了两个项目,分别为Elastic-Job-Lite和Elastic-Job-Cloud。Elastic-Job是一个分布式调度解决方案,由两个相互独立的子项目Elastic-Job-Lite和Elastic-Job-Cloud组成。
Elastic-Job-Lite定位为轻量级无中心化解决方案,使用jar包的形式提供分布式任务的协调服务。
Elastic-Job-Cloud使用Mesos +Docker(TBD)的解决方案,额外提供资源治理、应用分发以及进程隔离等服务,Elastic-Job-Lite和Elastic-Job-Cloud提供同一套API开发作业,开发者仅需一次开发,即可根据需要以Lite或Cloud的方式部署。
github: https://github.com/dangdangdotcom/elastic-job
Elastic-job提供3种类型作业:
1.Simple类型作业
2.Dataflow类型作业
3.Script类型作业
这里我们用第一种测试。
<dependency>
<groupId>com.dangdanggroupId>
<artifactId>elastic-job-springartifactId>
<version>1.1.1version>
dependency>
################################## Elastic-Job ##################################
regCenter.namespace=my-job
regCenter.zk.address=localhost1:2181,localhost2:2181
regCenter.baseSleepTimeMilliseconds=1000
regCenter.maxSleepTimeMilliseconds=3000
regCenter.maxRetries=3
regCenter.sessionTimeoutMilliseconds=10000
#如果为true,可以在控制台检测到作业的执行状态
job.monitorExecution=true
#失效转移,如果为true,当作业在执行过程中异常中断,作业会被分发到集群中存活的结点
job.failover=true
#如果为true,在开始部署的时候作业不会自启动,即使到了触发时间,需要在控制台手动触发。
job.disabled=false
#如果为true,则会覆盖zk的配置
job.overwrite=true
job.monitorPort=9888
#只有当分片的数量设置为1的时候,整个集群中只会有一个进程去执行该Job,在服务器数量没有波动的情况下,任务总会在固定某个进程上执行。在作业执行前进程如果挂了,那作业会被分配到集群某一个存活的进程中
job.shardingTotalCount=1
job.shardingItemParameters=
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:reg="http://www.dangdang.com/schema/ddframe/reg"
xmlns:job="http://www.dangdang.com/schema/ddframe/job"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.dangdang.com/schema/ddframe/reg
http://www.dangdang.com/schema/ddframe/reg/reg.xsd
http://www.dangdang.com/schema/ddframe/job
http://www.dangdang.com/schema/ddframe/job/job.xsd">
<reg:zookeeper id="regCenter"
server-lists="${regCenter.zk.address}"
namespace="${regCenter.namespace}-${env}"
base-sleep-time-milliseconds="${regCenter.baseSleepTimeMilliseconds}"
max-sleep-time-milliseconds="${regCenter.maxSleepTimeMilliseconds}"
max-retries="${regCenter.maxRetries}"
nested-port="-1"
session-timeout-milliseconds="${regCenter.sessionTimeoutMilliseconds}"/>
<job:simple id="myJob"
class="com.xx.job.MyJob"
registry-center-ref="regCenter"
sharding-total-count="${job.shardingTotalCount}"
cron="0/5 * * * * ?"
sharding-item-parameters="${job.shardingItemParameters}"
monitor-execution="${job.monitorExecution}"
monitor-port="${job.monitorPort}"
failover="${job.failover}"
description="我的job"
disabled="${job.disabled}"
overwrite="${job.overwrite}"/>
beans>
串行任务执行器
/**
* 串行任务执行器
*/
public abstract class AbstractSerialExecutor extends AbstractSimpleElasticJob {
public abstract void executeJob(String jobName);
@Override
public void process(JobExecutionMultipleShardingContext shardingContext) {
long t1 = System.currentTimeMillis();
executeJob(shardingContext.getJobName());
LogUtil.successJob(shardingContext.getJobName(), (System.currentTimeMillis() - t1));
}
}
并行任务执行器
/**
* 并行任务执行器
*/
public abstract class AbstractParallelExecutor extends AbstractSimpleElasticJob implements Runnable {
@Override
public void process(JobExecutionMultipleShardingContext shardingContext) {
something....
}
}
@Component
public class MyJob extends AbstractSerialExecutor {
private final static Logger logger = LoggerFactory.getLogger(MyJob.class);
@Override
public void executeJob(String jobName) {
System.out.println("*****************Myjob.....");
}
}
下载地址:https://github.com/elasticjob/elastic-job-lite/tree/dev/elastic-job-lite-console
具体怎么弄,可以去搜一个教程…
zookeeper里面保存了我们Job的信息:
我们把我们项目打成jar包,本地启动一个,另一台服务器也启动。我们发现只有一台服务器在运行定时任务:( 0/5 * * * * ?)每5秒跑一次…
这里我们做一个实验,我们假设一台服务器宕机了(现在在跑定时任务的主机),会怎么样?
使用Elastic-job轻松帮我们实现分布式定时任务,原理应该都一样。我推测:zookeeper的Leader选举,哪台机器被选为Leader,那他就跑任务。