1. 分布式任务调度问题

分布式任务调度有三个关键词:分布式、任务调度、配置中心。

  • 分布式:平台是分布式部署的,各个节点之间可以无状态和无限的水平扩展;
  • 任务调度:涉及到任务状态管理、任务调度请求的发送与接收、具体任务的分配、任务的具体执行;(这里又会遇到一共要处理哪些任务、任务要分配到哪些机器上处理、任务分发的时候判断哪些机器可以用等问题,所以又需要一个可以感知整个集群运行状态的配置中心)
  • 配置中心:可以感知整个集群的状态、任务信息的注册

分布式调度问题是由于分布式系统产生的任务调度问题,常见主要有两个问题:

  1. 由于是分布式系统,所以定时任务在同一时刻存在于多个服务实例运行,因此同一任务可能重复执行,数据可能产生重复或者其他问题
  2. 单一实例中的任务处理可能会因为数据量太大处理效率低下,由于单机处理,同时也会浪费其他的服务资源。

任务调度是指基于给定的时间点,给定的时间间隔或者给定执行次数自动的执行任务。任务调度是是操作系统的重要组成部分,而对于实时的操作系统,任务调度直接影响着操作系统的实时性能。任务调度涉及到多线程并发、运行时间规则定制及解析、线程池的维护等诸多方面的工作。

基于以上原因就产生了分布式任务调度框架。常见的分布式任务调度框架有:cronsun、Elastic-job、saturn、lts、TBSchedule、xxl-job等。它们的简单介绍如下:

  1. cronsum

cronsun是一个分布式任务系统,单个节点和Linux机器上的contab近似,是为了解决多台Linux机器上crontab任务管理不方便的问题,同时提供了任务高可用的支持(当某个节点死机的时候可以自动调整到正常的节点执行)。与此同时,它还支持界面管理机器上的任务,支持任务失败邮件提醒,安装简单,使用简便,是替换crontab的一个不错的选择。

  1. Elastic-job

Elastic-job是当当开源的一款非常好用的作业框架,Elastic-job在2.x之后,出现了两个相互独立的产品线:Elastic-job-lite和Elastic-job-cloud

  • Elastic-job-lite定位为轻量级无中心化的解决方案,使用jar包的形式提供分布式任务的协调服务,外部依赖仅依赖于zookeeper。
  • Elastic-job-cloud包含了Elastic-job-lite的全部功能,它是以私有云平台的方式提供集资源、调度以及分片为一体的全量级解决方案,依赖于Mesos和Zookeeper,它额外提供了资源治理、应用分发以及进程隔离等服务。他们两个提供同一套API开发作业,开发者仅需一次开发,然后可根据需要以lite或cloud的方式部署。
  1. Staurn

Saturn的基本原理是将作业在逻辑上划分为若干个分片,通过作业分片调度器将作业分片指派给特定的执行节点。执行节点通过quartz触发执行作业的具体实现,在执行的时候,会将分片序号和参数作为参数传入。作业的实现逻辑需分析分片序号和分片参数,并以此为依据来调用具体的实现

  1. LTS

LTS是一个轻量级分布式任务调度框架,主要用于解决分布式任务的调度问题,支持实时任务、定时任务和Cron任务,有较好的伸缩性、扩展性以及健壮稳定性。他参考hadoop的思想。

  1. Quartz

Quartz是OpenSymphony开源组织在任务调度领域的一个开源项目,完全基于java实现。作为一个优秀的开源框架,Quartz具有以下特点:强大的调度功能、灵活的应用方式、分布式和集群能力,另外作为spring默认的调度框架,很容易实现与Spring集成,实现灵活可配置的调度功能。

  1. TBSchedule

TBSchedule是一款非常优秀的分布式调度框架,广泛应用于阿里巴巴、淘宝、支付宝、京东、汽车之家等很多互联网企业的流程调度系统。TBSchedule在时间调度方面虽然没有quartz强大,但是它支持分片的功能。和quartz不同的是,TBSchedule使用zk来实现任务调度的高可用和分片。纯java开发

  1. xxl-job

xxl-job是一个轻量级的分布式任务调度框架,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。

Elastic-job作为一款非常好用的作业框架,虽然两年多没有维护了,但是基本不影响使用,本文只简单介绍Elastic-job的功能及使用

2. Elastic-Job介绍

Elastic-Job是当当网开源的一个分布式调度解决方案,基于Quartz二次开发的,由两个相互独立的子项 目Elastic-Job-Lite和Elastic-Job-Cloud组成。本文主要介绍 Elastic-Job-Lite,它定位为轻量级无中心 化解决方案,使用Jar包的形式提供分布式任务的协调服务,而Elastic-Job-Cloud子项目需要结合Mesos 以及Docker在云环境下使用。

  • Elastic-Job的github地址:Elastic-Job
  • Elastic-Job主要有以下功能
  1. 分布式调度协调:在分布式环境中,任务能够按指定的调度策略执行,并且能够避免同一任务多实例重复执行
  2. 丰富的调度策略 基于成熟的定时任务作业框架Quartz cron表达式执行定时任务
  3. 丰富的调度策略 基于成熟的定时任务作业框架Quartz cron表达式执行定时任务
  4. 失效转移 某实例在任务执行失败后,会被转移到其他实例执行
  5. 错过执行作业重触发 若因某种原因导致作业错过执行,自动记录错过执行的作业,并在上次作业 完成后自动触发。
  6. 支持并行调度 支持任务分片,任务分片是指将一个任务分为多个小任务项在多个实例同时执行。
  7. 作业分片一致性 当任务被分片后,保证同一分片在分布式环境中仅一个执行实例。
3. Elastic-Job-Lite应用
  • Elastic-Job依赖于Zookeeper进行分布式协调,所以需要安装Zookeeper软件,Elastic-Job基于3.4.6版本以上开发,所以安装版本必须高于3.4.6,安装步骤可参考zookeeper-3.6.1安装
  • 引入Jar包
<!-- https://mvnrepository.com/artifact/com.dangdang/elastic-job-lite-core -->
<!--elastic-job-lite核心包-->
<dependency>
    <groupId>com.dangdang</groupId>
    <artifactId>elastic-job-lite-core</artifactId>
    <version>2.1.5</version>
</dependency>
  • 简单使用示例
  1. 任务处理类
import com.dangdang.ddframe.job.api.ShardingContext;
import com.dangdang.ddframe.job.api.simple.SimpleJob;

public class MyJob implements SimpleJob {

    private DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    public void execute(ShardingContext shardingContext) {
        System.out.println(dateFormat.format(new Date()) + ":定时任务执行逻辑");
    }
}
  1. 任务配置及启动类
import com.dangdang.ddframe.job.config.JobCoreConfiguration;
import com.dangdang.ddframe.job.config.simple.SimpleJobConfiguration;
import com.dangdang.ddframe.job.lite.api.JobScheduler;
import com.dangdang.ddframe.job.lite.config.LiteJobConfiguration;
import com.dangdang.ddframe.job.reg.base.CoordinatorRegistryCenter;
import com.dangdang.ddframe.job.reg.zookeeper.ZookeeperConfiguration;
import com.dangdang.ddframe.job.reg.zookeeper.ZookeeperRegistryCenter;

public class ElasticJobMain {

    public static void main(String[] args) {
        // 配置分布式协调服务(注册中心)Zookeeper
        ZookeeperConfiguration zookeeperConfiguration = new ZookeeperConfiguration("localhost:2181","data-archive-job");
        CoordinatorRegistryCenter coordinatorRegistryCenter = new ZookeeperRegistryCenter(zookeeperConfiguration);
        coordinatorRegistryCenter.init();
        
        // 配置任务(时间事件、定时任务业务逻辑、调度器)
        JobCoreConfiguration jobCoreConfiguration = JobCoreConfiguration
                .newBuilder("archive-job", "*/2 * * * * ?", 1).build();
        SimpleJobConfiguration simpleJobConfiguration = new SimpleJobConfiguration(jobCoreConfiguration,MyJob.class.getName());

        JobScheduler jobScheduler = new JobScheduler(coordinatorRegistryCenter, LiteJobConfiguration.newBuilder(simpleJobConfiguration).overwrite(true).build());
        jobScheduler.init();
    }
}
  1. 任务执行结果

在这里插入图片描述

  • Elastic-Job-Lite主要是为分布式多个实例服务的,我们可以模拟多个实例测试,方法如下
    1)可先启动一个进程,然后再启动一个进程(两个进程模拟分布式环境下,一个定时任务 部署了两份在工作)
    2)两个进程逐个启动,观察现象
    3)关闭其中执行的进程,观察现象
  • IDEA 主类中的main方法只能执行一次,可以设置启动多个main方法,设置方式如下
    在这里插入图片描述
  • 通过测试可以观察到,启动一个服务A时,定时任务在A中正常执行,然后启动服务B,这个时候定时任务在B中执行,A中没有执行,然后关掉服务B,定时任务又重新再服务A执行。
  • 所以不管部署了多少个实例,定时任务同一时刻只在一个服务执行,当其中的一个服务或者多个服务关闭时,定时任务会自动切换到正常的服务中执行。这就实现了分布式调度协调:在分布式环境中,任务能够按指定的调度策略执行,并且能够避免同一任务多实例重复执行以及失效转移的功能
4. 任务分片

一个大的非常耗时的作业Job,比如:一次要处理一亿的数据,那这一亿的数据存储在数据库中,如果 用一个作业节点处理一亿数据要很久,在互联网领域是不太能接受的,互联网领域更希望机器的增加去 横向扩展处理能力。所以,ElasticJob可以把作业分为多个的task(每一个task就是一个任务分片),每 一个task交给具体的一个机器实例去处理(一个机器实例是可以处理多个task的),但是具体每个task 执行什么逻辑由我们自己来指定。

在这里插入图片描述

Strategy策略定义这些分片项怎么去分配到各个机器上去,默认是平均去分,可以定制,比如某一个机 器负载 比较高或者预配置比较高,那么就可以写策略。分片和作业本身是通过一个注册中心协调的,因 为在分布式环境下,状态数据肯定集中到一点,才可以在分布式中沟通。

  • 分片代码如下,在上面的代码下稍微改动即可

在这里插入图片描述
在这里插入图片描述

  • 上述代码表示分片数量为3个,如果存在三个服务实例,定时任务会均匀的分配到这三个服务器上,shardingContext可以获取当前是哪个分片以及分片的参数,然后当前实例根据这个参数选取自己要处理的任务,这样就可以达到多个实例同时的处理一个定时任务,以实现最大化的处理能力。
5. 弹性扩容

在这里插入图片描述

  • 如上图所示,当前有两个实例APP1,APP2,task0分配到APP1执行,task1 task2分配到APP2执行,新增加一个运行实例APP3,它会自动注册到注册中心,注册中心发现新的服务上线,注册中心会通知 ElasticJob 进行重新分片,所以总的分片项有多少,那么就可以搞多少个实例机器,比如完全可以分 1000片, 那么就可以搞1000台机器一起执行作业
    注意:
  1. 分片项也是一个JOB配置,修改配置,重新分片,在下一次定时运行之前会重新调用分片算法,那么 这个分片算法的结果就是:哪台机器运行哪一个一片,这个结果存储到zk中的,主节点会把分片给分好放到注册中心去,然后执行节点从注册中心获取信息(执行节点在定时任务开启的时候获取相应的分片)。
  2. 如果所有的节点挂掉值剩下一个节点,所有分片都会指向剩下的一个节点,这也是ElasticJob的高可 用。
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐