Elastic Job学习(三)执行作业

流程图:
Elastic Job学习(三)执行作业_第1张图片
SimpleJob为例说明 :

1、通过LiteJob实现quartz的Job接口,elastic job与quartz联系在一起,最终作业按cron配置的时间来触发。作业启动时,会依据job的类型,由作业执行工厂JobExecutorFactory创建相应的作业执行器,并执行execute()方法。

public static AbstractElasticJobExecutor getJobExecutor(final ElasticJob elasticJob, final JobFacade jobFacade) {
        if (null == elasticJob) {
            return new ScriptJobExecutor(jobFacade);
        }
        if (elasticJob instanceof SimpleJob) {
            return new SimpleJobExecutor((SimpleJob) elasticJob, jobFacade);
        }
        if (elasticJob instanceof DataflowJob) {
            return new DataflowJobExecutor((DataflowJob) elasticJob, jobFacade);
        }
        throw new JobConfigurationException("Cannot support job type '%s'", elasticJob.getClass().getCanonicalName());
    }

2、作业启动之前,会先检查Job的执行环境,主要是检查本机(作业服务器)与注册中心的时间误差(秒),是否在允许范围.
即max-time-diff-seconds属性,

  • 没有配置(max-time-diff-seconds 默认为 -1),则跳过校验;

  • 配置了,则获取zk的时间,与本机时间进行比较,是否超过max-time-diff-seconds

获取zk的时间,是在作业节点下创建永久节点systemTime/current,获取该节点的属性mtime

3、获取分片信息

  • 判断是否需要分片,不需要则直接返回;
  • 需要分片(是否存在临时节点Leader/sharding/necessary),且有可用的作业实例,再判断是否存在主节点,不存在则等待选举完成 ;
  • 选举完成后,判断当前服务器是否为主节点,是主节点,则进行分片;
  • 不是主节点,则等待(休眠100ms)主节点完成分片;
  • 分片时,创建临时节点leader/sharding/processing标识正在分片,其它作业启动时,会检查分片是否完成,如果正在分片,则需要阻塞(100ms)并等待分片完成
  • 如果配置了自定义的分片策略(实现JobShardingStrategy接口),则使用自定义的策略,如果没有配置,则使用默认的策略(平均分片算法AverageAllocationJobShardingStrategy)
  • 分片成功之后,回调PersistShardingInfoTransactionExecutionCallback,该回调主要是创建分片节点(sharding/0…N),以及删除Leader/sharding/necessary和Leader/sharding/processing节点
    在这里,可以学到下ZK事务操作CuratorTransactionFinal。

4、分片完成之后,会获取本机对应的分片项及实例,根据IP来选择,最终将属于本机的分片项,封装为ShardingContexts返回;

5、LiteJobFacade.beforeJobExecuted埋点,用来供用户配置了自定义的listener,在Job运行之前执行;

6、注册Job开始运行的信息,即创建节点shardings/分片序号/running节点

7、执行作业:

  • 获取作业的分片项,即该分片对应的实例列表,如4台服务器分2片,则0分片获取的是1,2,1分片获取3,4;
  • 如果分片上只有一个实例,则直接运行
  • 如果有多个实例,则使用线程池,逐个启动;
    最终会调用我们实现的SimpleJob(或其它两种Job),执行process方法,对于多实例的作业,只有全部实例都执行完成后,才统一返回。
//分片多线程处理
        final CountDownLatch latch = new CountDownLatch(items.size());
        for (final int each : items) {
            final JobExecutionEvent jobExecutionEvent = new JobExecutionEvent(shardingContexts.getTaskId(), jobName, executionSource, each);
            if (executorService.isShutdown()) {
                return;
            }
            executorService.submit(new Runnable() {
                
                @Override
                public void run() {
                    try {
                        process(shardingContexts, each, jobExecutionEvent);
                    } finally {
                        latch.countDown();
                    }
                }
            });
        }
        
        try {
            latch.await();
        } catch (final InterruptedException ex) {
            Thread.currentThread().interrupt();
        }

作业执行类图:
Elastic Job学习(三)执行作业_第2张图片

你可能感兴趣的:(java)