对于分布式Job的思考

编程


引言

在清理Github的时候,发现以前写的一个简单的分布式任务分发系统ClawHub/task-distribution,使用了zk的选主与队列,调度器使用spring的ThreadPoolTaskScheduler,任务支持cron表达式。

这让我想起在这之前还封装过Quartz,那时候做的是单机版超大型应用,内部需要做调度系统。

目前在公司使用过Elastic-Job,也使用过Spring自带调度与ZK的结合,还有公司Boss系统提供的配置版本任务调度。

写这篇文章主要是简单的回忆一下Quartz与Spring的ThreadPoolTaskScheduler,还有Elastic-job。再写一下自己对分布式Job的思考。

1、quartz

官网地址:quartz-scheduler.org

1.1、简单使用

maven的pom文件:

<dependency>

<groupId>org.quartz-scheduler</groupId>

<artifactId>quartz</artifactId>

<version>2.3.2</version>

</dependency>

具体任务:

import org.quartz.Job;

import org.quartz.JobExecutionContext;

import java.time.LocalDateTime;

import java.util.Random;

public class HelloJob implements Job {

@Override

public void execute(JobExecutionContext jobExecutionContext) {

System.out.println(jobExecutionContext.getJobDetail().getJobDataMap().get("jobDetailJobData1"));

System.out.println(jobExecutionContext.getTrigger().getJobDataMap().get("triggerJobData1"));

System.out.println("HelloJob start at:" LocalDateTime.now() ", prints: Hello Job-" new Random().nextInt(100));

}

}

主调度器:

import org.quartz.*;

import org.quartz.impl.StdSchedulerFactory;

import java.util.concurrent.TimeUnit;

public class MainScheduler {

public static void main(String[] args) throws SchedulerException, InterruptedException {

// 1、创建调度器Scheduler

SchedulerFactory schedulerFactory = new StdSchedulerFactory();

Scheduler scheduler = schedulerFactory.getScheduler();

// 2、创建JobDetail实例,并与PrintWordsJob类绑定(Job执行内容)

JobDetail jobDetail = JobBuilder.newJob(HelloJob.class).usingJobData("jobDetailJobData1", "测试JobDetail上下文")

.withIdentity("job1", "group1").build();

// 3、构建Trigger实例,每隔1s执行一次

Trigger trigger = TriggerBuilder.newTrigger().usingJobData("triggerJobData1", "测试Trigger上下文")

.withIdentity("trigger1", "triggerGroup1")

.startNow()//立即生效

.withSchedule(SimpleScheduleBuilder.simpleSchedule()

.withIntervalInSeconds(1)//每隔1s执行一次

.repeatForever()).build();//一直执行

//4、执行

scheduler.scheduleJob(jobDetail, trigger);

System.out.println("--------MainScheduler start ! ------------");

scheduler.start();

//睡眠

TimeUnit.MINUTES.sleep(1);

scheduler.shutdown();

System.out.println("--------MainScheduler shutdown ! ------------");

}

}

经过上面三步,执行main方法,就可以简单的实现调度任务了,下面分别介绍出现的角色。

1.2、角色介绍

1.2.1、Job和JobDetail

Job是Quartz中的任务模板,JobDetail是Job的描述,当Scheduler执行任务的时候,会根据JobDetail创建新的Job,用过之后就释放掉。

1.2.2、Trigger

触发器,描述了任务是什么时候触发执行,常用有SimpleTrigger、CronTrigger,cron表达式非常强大,基本上都是基于CronTrigger来做任务调度。

1.2.3、JobDataMap与JobExecutionContext

JobExecutionContext任务执行的上下文,JobDataMap保存上下文传输的数据。

1.1、架构原理

上面这幅图可以简单的描述Quartz核心对象之间的关系。

2、Spring的ThreadPoolTaskScheduler

底层依赖于JUC的java.util.concurrent.ScheduledExecutorService。

2.1、简单使用

import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

import org.springframework.scheduling.support.CronTrigger;

import java.time.LocalDateTime;

import java.util.Random;

public class Main {

public static void main(String[] args) {

ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();

scheduler.setPoolSize(10);

scheduler.initialize();

scheduler.schedule(() -> {

System.out.println("HelloJob start at:" LocalDateTime.now() ", prints: Hello Job-" new Random().nextInt(100));

}, new CronTrigger("0/1 * * * * ?"));

}

}

3、Elastic-Job

Elastic-Job是一个分布式调度解决方案,由两个相互独立的子项目Elastic-Job-Lite和Elastic-Job-Cloud组成。

官网:elasticjob.io。

我们使用的是轻量级的使用方案:elasticjob/elastic-job-lite

官方架构图:

作业执行流程图:

我也只有使用经验,并没有深入的了解其原理,具体请参考官方文档。

4、对于分布式Job的思考

现在的Quartz也有集群版本,我还没有接触过,现在碰到的基本上都是基于Quartz的包装,比如Elastic-Job、xxl job、azkaban。

因为现在的项目基本都为分布式系统,所以对于调度系统而言,单机已经不怎么适用了。

而对于分布式调度系统,必然也有很多要求,下面讲一下我的理解:

  • 任务定时完成

    这个式调度系统的基本要求。

  • 任务可分片

    对于一些大量数据的定时任务,如果只在一台机器上执行是很吃力的,所以应该有任务分片执行的功能,将大任务拆分到多个系统上执行。

  • 弹性扩容缩容

    在增加或者减少节点时,任务能够自动均衡。

  • 任务可配置

    任务的信息可动态配置。

  • 任务动态操作

    任务动态地启动、暂停、终止、删除等。

  • 去中心化

    任务的执行与否由各个节点自己控制,但是要保证任务执行不可重复。

  • 故障转移

    节点发生故障时,任务自动转移。

  • 任务执行记录

    任务的执行信息需要有记录。

能想到这只有这么多,感觉Elastic-Job就很好用。

以上是 对于分布式Job的思考 的全部内容, 来源链接: utcz.com/z/511532.html

回到顶部