基于Linux Crontab的定时任务执行器为例进行介绍。其存在如下问题:
除了Linux Crontab,在Java这块的方案还有Quartz,但Quartz缺少分布式并行调度的功能。其问题很明显:
在分布式架构环境中使用Quartz已经不能更好的满足我们需求,我们需要使用专业的分布式调度框架,这里介绍下Elastic-job。
Elastic-Job是当当网开源的一个分布式任务调度解决方案,基于Quartz二次开发的,由两个相互独立的子项 目Elastic-Job-Lite和Elastic-Job-Cloud组成。
Elastic-Job-Lite:为轻量级无中心化解决方案,使用JAR包提供分布式任务的调度和治理。
Elastic-Job-Cloud:使用Mesos+Docker的解决方案,额外提供资源治理、应用分发及进程隔离等服务。
官网地址:http://elasticjob.io/
github地址:https://github.com/elasticjob
Elastic-Job依赖于Zookeeper进行分布式协调,所以需要安装Zookeeper软件。
zookeeper是一个开源的分布式协调服务,提供分布式数据一致性解决方案,分布式应用程序可以实现数据发布订阅、负载均衡、命名服务、集群管理分布式锁、分布式队列等功能。不做详细赘述。
Zookeeper是安装Kafka集群的必要组件,Kafka通过Zookeeper来实施对元数据信息的管理,包括集
群、主题、分区等内容。
ZooKeeper官网:http://zookeeper.apache.org/
修改Zookeeper的配置文件,首先进入安装路径conf目录,并将zoo_sample.cfg文件修改为 zoo.cfg,并对核心参数进行配置。
Zookeeper配置文件详解
# The number of milliseconds of each tick # zk服务器的心跳时间
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
# 投票选举新Leader的初始化时间
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
# do not use /tmp for storage, /tmp here is just # example sakes.
# 数据目录
dataDir=temp/zookeeper/data
# 日志目录
dataLogDir=temp/zookeeper/log
# the port at which the clients will connect
# Zookeeper对外服务端口,保持默认
clientPort=2181
启动zookeeper
[root@localhost bin]# ./zkServer.sh start
ZooKeeper JMX enabled by default
Using config: /opt/zookeeper-3.4.14/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
其他操作
停止 ./zkServer.sh stop
查看状态 ./zkServer.sh status
<!-- https://mvnrepository.com/artifact/com.dangdang/elastic-job-lite-core -->
<dependency>
<groupId>com.dangdang</groupId> <artifactId>elastic-job-lite-core</artifactId> <version>2.1.5</version>
</dependency>
public class ElasticjobMainNoShard {
public static void main(String[] args) {
ZookeeperConfiguration zookeeperConfiguration = new ZookeeperConfiguration("172.16.115.129:2181","data-archive-job-add");
CoordinatorRegistryCenter coordinatorRegistryCenter = new ZookeeperRegistryCenter(zookeeperConfiguration);
coordinatorRegistryCenter.init();
// 配置任务(时间事件、定时任务业务逻辑、调度器)
JobCoreConfiguration jobCoreConfiguration = JobCoreConfiguration
.newBuilder("archive-job-add", "*/1 * * * * ?", 1).build();
SimpleJobConfiguration simpleJobConfiguration = new SimpleJobConfiguration(jobCoreConfiguration, ArchivieJobInsert.class.getName());
JobScheduler jobScheduler = new JobScheduler(coordinatorRegistryCenter, LiteJobConfiguration.newBuilder(simpleJobConfiguration).overwrite(true).build());
jobScheduler.init();
}
}
在分布式环境中,任务能够按指定的调度策略执行,并且能够避免同一任务多实例重复执行,当开启一个服务执行任务时,会将leader设置为开启的服务,当开启两个任务时,leader由于被服务二抢走,服务一会停止继续执行。保证只有一个会去执行。
一个大的非常耗时的作业Job,比如:一次要处理一亿的数据,那这一亿的数据存储在数据库中,如果用一个作业节点处理一亿数据要很久,在互联网领域是不太能接受的,互联网领域更希望机器的增加去横向扩展处理能力。所以,ElasticJob可以把作业分为多个的task(每一个task就是一个任务分片),每 一个task交给具体的一个机器实例去处理(一个机器实例是可以处理多个task的),但是具体每个task 执行什么逻辑由我们自己来指定。
Strategy策略定义这些分片项怎么去分配到各个机器上去,默认是平均去分,可以定制,比如某一个机 器负载 比较高或者预配置比较高,那么就可以写策略。分片和作业本身是通过一个注册中心协调的,因为在分布式环境下,状态数据肯定集中到一点,才可以在分布式中沟通。
public class ElasticjobMainShard {
public static void main(String[] args) {
ZookeeperConfiguration zookeeperConfiguration = new ZookeeperConfiguration("172.16.115.129:2181","data-archive-job");
CoordinatorRegistryCenter coordinatorRegistryCenter = new ZookeeperRegistryCenter(zookeeperConfiguration);
coordinatorRegistryCenter.init();
// 配置任务(时间事件、定时任务业务逻辑、调度器)
JobCoreConfiguration jobCoreConfiguration = JobCoreConfiguration
.newBuilder("archive-job", "*/2 * * * * ?", 3)
.shardingItemParameters("0=bachelor,1=master,2=doctor").build();
SimpleJobConfiguration simpleJobConfiguration = new SimpleJobConfiguration(jobCoreConfiguration, ArchivieJobShard.class.getName());
JobScheduler jobScheduler = new JobScheduler(coordinatorRegistryCenter, LiteJobConfiguration.newBuilder(simpleJobConfiguration).overwrite(true).build());
jobScheduler.init();
}
}
支持并行调度支持任务分片,任务分片是指将一个任务分为多个小任务项在多个实例同时执行。
当开启三个服务时,每个服务各自会处理一个分片。
当某一个或某几个服务挂掉后,会由活着的服务自动帮助处理任务。
关闭个后,其中一个服务会处理连个任务,另一个服务会处理一个任务。