1什么是分布式任务调度

1.1任务举例-定时任务

1.1.1实际案例

1.1.1.1网贷-日终任务

1.1.1.2其它业务-全日频繁

1.1.1.3 Crontab、shell

 

1.2产生问题 PK 解决问题

1.2.1迎面遇到第一个问题:集群重复执行

每台虚机在同一时间都会执行定时任务:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

尝试解决:将任务单独拆出放入一台虚机(TASK)。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

产生新的问题:

1.即便TASK 100%可靠永远不宕。也有极大的停机风险,不确定在停机期间是否有任务被遗漏(misfire)。

2.任务更多,更复杂,占越来越多的资源,性能问题凸显,任务队列阻塞风险。

 

 

 

 

 

1.2.2Quartz集群

 

 

 

 

 

 

 

 

 

 

 

 

 

之后看了眼quartz官方logo,感觉自己萌萌的。

 

 

1.2.3管理、调度任务产生问题

萌不过三天。发现这个定时任务策略要修改,

同样,下面这个任务不需要做,取消掉

也无法及时监控:报错了吗,运行成功了吗?

随着业务发展暴露出越来越多的问题:

 

 

 

 

 

 

 

 

 

 

 

 

例如:

 

----截图摘自沈建林“分布式调度系统介绍”中的五个问题

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1.2.4解决问题 解决问题 解决问题

集思广益造轮子:

Quartz,Xxl-job,elastic-job,tbschedule,uncode-schedule,Opencron

 

在分布式环境中如何将任务集群中分散的、可靠性差的任务统一化管理和调度,实现分布式部署的管理方式,这就是分布式任务调度。

 

 

 

 

 

 

 

 

 

 

 

 

 

2.分布式任务调度框架

2.1初识

2.1.1Ferrari

https://www.cnblogs.com/xuxueli/p/5021979.html

 

XXL-JOB框架2015-11月发布1.0.RELEASE

2016-01月,大众点评接入XXL-JOB内部别名《Ferrari》。 2016-01-21接入至2017-12-01期间,该系统已调度约100万次,经过数个大版本的更新,系统的任务模型、UI交互模型以及底层调度通讯模型都有了较大的优化和提升,核心功能更加稳定高效。

 

 

 

 

2.1.2Elastic-Job

http://elasticjob.io/

Elastic-Job分为Elastic-Job-LiteElastic-Job-Cloud

2.1.3Tbschedule

http://code.taobao.org/p/tbschedule/src/

 

http://code.taobao.org/p/tbschedule/wiki/tbschedule-quick-start/

 

 

2.1.4Uncode-Schedule

https://gitee.com/uncode/uncode-schedule/releases

2.2基础

2.2.1Quartz

 

2.2.1.1Quartz初体验

2.2.1.1.1Example1

 

当然也支持cron表达式如下,运行结果略。

 

 

 

 

 

 

 

 

2.2.1.1.2Example2-CronTrigger Misfire

Misfire策略

withMisfireHandlingInstructionDoNothing:不触发立即执行,等待下次调度; withMisfireHandlingInstructionIgnoreMisfires:以错过的第一个频率时间立刻开始执行; withMisfireHandlingInstructionFireAndProceed:以当前时间为触发频率立刻触发一次执行;

 

准备工作:

Job:

 

Misfires strategy1:

withMisfireHandlingInstructionIgnoreMisfires:以错过的第一个频率时间立刻开始执行;

 

Misfires strategy2:

withMisfireHandlingInstructionDoNothing:不触发立即执行,等待下次调度;

 

 

Misfires strategy3:

withMisfireHandlingInstructionFireAndProceed:以当前时间为触发频率立刻触发一次执行

 

 

 

2.2.1.2Quartz组件关系

2.2.1.2.1Quartz组件

 

 

 

 

QuartzSchedulerThread :负责执行向QuartzScheduler注册的触发Trigger的工作的线程。 
ThreadPoolScheduler使用一个线程池作为任务运行的基础设施,任务通过共享线程池中的线程提供运行效率。 
QuartzSchedulerResources:包含创建QuartzScheduler实例所需的所有资源(JobStoreThreadPool等)。 
SchedulerFactory :提供用于获取调度程序实例的客户端可用句柄的机制。 
JobStore 通过类实现的接口,这些类要为org.quartz.core.QuartzScheduler的使用提供一个org.quartz.Joborg.quartz.Trigger存储机制。作业和触发器的存储应该以其名称和组的组合为唯一性。 
QuartzScheduler :这是Quartz的核心,它是org.quartz.Scheduler接口的间接实现,包含调度org.quartz.Jobs,注册org.quartz.JobListener实例等的方法。 
Scheduler :这是Quartz Scheduler的主要接口,代表一个独立运行容器。调度程序维护JobDetails和触发器的注册表。 一旦注册,调度程序负责执行作业,当他们的相关联的触发器触发(当他们的预定时间到达时)。 
Trigger :具有所有触发器通用属性的基本接口,描述了job执行的时间出发规则。 - 使用TriggerBuilder实例化实际触发器。 
JobDetail :传递给定作业实例的详细信息属性。 JobDetails将使用JobBuilder创建/定义。 
Job:要由表示要执行的作业的类实现的接口。只有一个方法 void execute(jobExecutionContext context) 
(jobExecutionContext 提供调度上下文各种信息,运行时数据保存在jobDataMap
Job有个子接口StatefulJob ,代表有状态任务。 
有状态任务不可并发,前次任务没有执行完,后面任务处于阻塞等到。

2.2.1.2.2组件关系简要

 

 

 

 

 

 

2.2.1.2.3生命周期

只列重点不展开,用Quartz官网Example1

2.2.1.2.3.1Scheduler

(1)Scheduler

Instantiate()这是一个近千行的方法,

 

 

 

 

 

(1-1)Scheduler Members

(2)JobStore

 

 

(3)ThreadExecutor

 

 

 

(4)QuartzSchedulerThread

(4-1)run()

(4-2)sigLock.await()

 

 

 

 

(5)Job run

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2.2.1.2.3.2Scheduler-start()-notifyAll()

 

 

2.2.2Spring-task

2.2.2.1TaskExecutor

2.2.2.2TaskScheduler

2.2.2.3Using the Quartz Scheduler

2.3方式

2.3.1抢占式

2.3.1.1 Quartz

 

2.3.1.1.1JobStore

 

 

 

 

 

 

2.3.1.1.2Lock & Trigger

 

 

 

 

 

2.3.1.1.3时序图

2.3.1.2 Uncode-Schedule

2.3.1.2.1功能概述

  1. 基于zookeeper+spring task/quartz的分布任务调度系统。
  2. 确保每个任务在集群中不同节点上不重复的执行。
  3. 单个任务节点故障时自动转移到其他任务节点继续执行。
  4. 任务节点启动时必须保证zookeeper可用,任务节点运行期zookeeper集群不可用时任务节点保持可用前状态运行,zookeeper集群恢复正常运期。
  5. 支持动态添加和删除任务。
  6. 添加ip黑名单,过滤不需要执行任务的节点。
  7. 简单管理后台

 

 

2.3.1.2.2架构

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2.3.1.2.3ZKScheduleManager

 

继承ThreadPoolTaskScheduler,重写下图方法:

在子类和父类中任选一个方法对比,比如scheduleAtFixedRate()方法:

子类:

父类:

发现即是在第一个入参Runnable task包装了一个taskWrapper(task)

在容器启动以及心跳刷新服务的时候,会在zookeeper上创建节点

在节点

”/uncode_test/schedule/task/helloWorld#hi”

下面会有ip+uuid+seqno,在taskWrapper()中的isOwner即是根据此标识字符串:

“192.168.236.1$FA2165482C644A899076A9542BF68C25$0000000008”

每个机器自己均持有各自的标识字符串,任一时刻至多只有一台匹配的机器,持有匹配字符串的机器才能执行

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2.3.1.2.4心跳-刷新任务节点

 

 

 

2.3.1.2.5Uncode schedule与Quartz集成

 

 

 

 

2.3.1.2.6监控

 

2.3.1.3 Elastic-job-site

官网:http://elasticjob.io/

2.3.1.3.1配置

2.3.1.3.2任务/分片 demo

 

2.3.2协同式

2.3.2.1 Xxl-job

2.3.2.1.1功能概述

https://www.cnblogs.com/xuxueli/p/5021979.html

 

2.3.2.1.2调度关系

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2.3.2.1.3管理中心

 

路由策略

 

 

 

 

 

 

 

2.3.2.1.4管理端服务AdminBiz

XxlJobDynamicScheduler

服务发现+失败预警+远程触发

 

 

 

  1. 服务发现

JobRegistryMonitorHelper.getInstance().start();

执行器注册到registry,管理中心不断扫描同步注册进来的执行器至group中。

 

 

 

 

 

 

 

 

 

 

 

  1. 失败预警

JobFailMonitorHelper.getInstance().start();

 

(3)RemotehttpJobBean

参见Uncode-Schedule与Quartz集成

 

 

 

(4)XxlJobTrigger策略模式按策略触发任务

 

 

 

 

 

 

(5)NetComClientProxy代理模式远程调用Executor

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

(6)路由策略

(6-1)第一个

(6-2)一致hash

 

(6-3)分片广播

对比其它策略的相同方法:

 

 

 

(6-4)failover

 

(6-5)busyover

(6-5)其它

其它策略:最后一个,轮询,随机,最不经常使用,最近最久不使用:略。

也可自己定制。

(7)Misfire

XXL-JOB默认misfire规则为:withMisfireHandlingInstructionDoNothing

2.3.2.1.5执行器端服务ExecutorBiz

(1)XxlJobExecutor

 

 

 

 

 

 

 

(1-1)NetComClientProxy代理模式远程调用Admin

 

 

(1-2)加载任务bean

(1-3)服务注册

 

 

 

 

 

 

 

 

 

 

 

(2)JettyServerHandler准备执行任务

(3)ExecutorBizImpl如何执行任务

 

(4)TriggerParam

2.3.3对比

抢占式:谁先获得资源谁就能执行,这种模式无法将单个任务的数据交给其它节点协同处理,一般用于处理数据量较小,任务较多的场景下。

 

协同式:可以将单个任务处理的数据分配到多个JVM中处理,提高数据的并行处理能力,能够充分利用计算机资源。

 

 

2.4补充

 

2.4.1Tbschedule & Uncode schedule

TbSchedule:

Uncode schedule:

TbSchedule:

 

Uncode schedule:

 

 

 

 

 

 

 

 

 

2.4.2作业分片

作业分片只是个逻辑概念,分片和实际数据其实框架是不做任何匹配关系的。而根据分片项和实际业务如何关联按业务自定义。

  1. 将一个数据表中所有数据的ID按10取模,就将数据划分成了0、1、2、3、4、5、6、7、8、9供10个任务项。
    2、将一个目录下的所有文件按文件名称的首字母(不区分大小写), 就划分成了A、B、C、D、E、F、G、H、I、J、K、L、M、N、O、P、Q、R、S、T、U、V、W、X、Y、Z供26个任务项。
    3、将一个数据表的数据ID哈希后按1000取模作为最后的HASHCODE,我们就可以将数据按[0,100)、[100,200) 、[200,300)、[300,400) 、[400,500)、[500,600)、[600,700)、[700,800)、[800,900)、 [900,1000)划分为十个任务项。

 

 

 

 

 

 

3.开源

 

01-14 03:42