调度属性配置

概述

什么是调度

在典型的批处理场景中,任务都是周期性的运行(例如每天运行一次),且不同的任务之间会存在上下游依赖关系,例如数据抽取任务会首先运行,之后才运行SQL处理任务。在这一过程中,周期性、任务的上下游依赖关系就是「调度」的基本概念,调度系统的职责可以归结为2方面:

  • 生成周期实例:参考实例的生成

  • 按计划运行实例:由于任务之间存在上下游关系(有些同时存在自依赖),需判断任务是否到达了运行的条件

用户可以在离线开发中进行调度属性的配置,主要包含调度周期配置、上下游依赖性、跨周期依赖、任务优先级配置等内容

基本原则

调度系统的基本原则分为以下2类:

判断任务运行条件

每天按计划运行周期实例时,调度系统判断一个实例是否可以运行,需满足2方面条件:

  • 任务的计划时间

  • 上游任务是否全部成功

若不能同时满足以上2个条件,则任务会处于等待提交状态。满足以上2个条件时,此任务在调度系统中具备了运行的条件,调度系统会将任务「提交」至计算引擎(任务进度等待运行状态),此任务还需要获得集群的计算资源,集群资源的分配由计算集群分配,用户不可干预,因此,满足时间+上下游依赖条件,并不意味着任务会立即开始运行,其可能在等待计算资源

例如,某任务A计划时间为每天02:00,上游依赖B、C、D 3个任务,那么判断A任务是否可运行,其判断逻辑为:

  • 当前时间>=02:00

  • 上游任务B、C、D是否全部为成功状态

寻找上游实例

在任务的周期性、上下游、跨周期等各种场景,尤其是不同周期的任务相互依赖,调度系统进行依赖判断的基本原则是:

  • 第一条:当前实例寻找上游实例时,永远会去寻找一个与其计划时间相等,或之前的实例,不会去寻找未来时间的实例

  • 第二条:这一原则仅在如下条件下会被打破:当均为天任务时,会在当天的实例中,寻找上游任务的实例

对这一原则的场景化描述请参考几种典型场景

任务与实例

任务与实例是一对多的关系,在「数据开发」模块中配置的SQL任务、同步任务,其中包含代码、配置信息等,这是一个任务(Job),一个任务每运行一次,被称作一个实例(Instance)。任务是固定的一个配置,将一个任务运行多次,每次的结果、数据产出都不一样,在概念上进行区分是很有必要的。在本文的描述中,「任务」和「实例」可能会混用,读者需结合上下文理解其实际含义

周期性

周期粒度

在「数据开发」模块,任意打开一个任务,可在其右侧的「调度依赖」面板中,可配置「调度周期」为天、周、月、小时、分钟及自定义,若选中 ,则表示此任务每天执行一次

调度周期 起调时间配置

天调度任务,即每天自动运行一次。新建周期任务时,默认的时间周期为每天0点运行一次,可根据需要自行指定运行时间点,配置"具体时间":
- 小时:单选下拉列表,00-23,默认选中00
- 分钟:单选下拉列表,00-59,默认选中00

周调度任务,即每周的特定几天里每天在特定时间点自动运行一次,需配置 选择时间具体时间
- 选择时间:复选下拉列表{星期一;星期二;…​…​星期日},可复选,默认选中 星期一
- 具体时间:同 调度周期-日 相同;

月调度任务,即每月指定的特定几天里每天在特定时间点自动运行一次,需配置 选择时间具体时间
- 选择时间:复选下拉列表{每月最后一天;每月1号;每月2号;…​…​每月31号},可复选,默认选中 星期一
- 具体时间:同 调度周期-日 相同;

小时

小时调度任务,即每天指定的时间段内按N*1小时的时间间隔运行一次,比如每天1点到4点的时间段内,每1小时运行一次。当调度周期切换到非天级调度时,节点起调时间将不可选,需配置 开始时间结束时间间隔时间
- 开始时间、结束时间:同 调度周期-日 类似,小时可选择00-23,分钟不可选,开始时间的分钟为0,结束时间的分钟为59;
- 间隔时间:单选下拉列表{1小时;2小时…​…​23小时},默认选中1小时;
- 开始时间,应早于结束时间 ;

分钟

分钟调度任务,即每天指定的时间段内按N*指定分钟的时间间隔运行一次,目前能支持的最短时间间隔为每5分钟运行一次,当调度周期切换到非天级调度,节点起调时间将不可选,需配置 开始时间结束时间间隔时间
- 开始时间、结束时间:同 调度周期-小时 相同;
- 间隔时间:单选下拉列表{5分钟;10分钟;…​…​55分钟},默认选中5分钟;
- 开始时间,应早于结束时间

自定义

填写Cron表达式,填写后可预览未来10个实例的计划时间

  • 按照小时周期调度时,时间周期按左闭右闭原则计算,比如配置为从0点到2:59点的时间段内,每隔1个小时运行一次,表明时间区间为[00:00,02:59],间隔为1小时,调度系统将会每天生成3个实例,分别在0:00/1:00/2:00运行。

  • 离线开发支持的最小调度间隔为5分钟,不支持更短的调度周期,若存在此种场景,可考虑实时计算等其他解决方案

  • 具体时间并不表示任务的实际开始时间,系统可能会因为上游任务延迟、集群资源紧张等原因造成延迟执行

生效日期

  • 指当前调度任务的调度生效日期范围,默认为100年,若有特殊需要可以修改此时间范围

  • 超出生效日期后,此调度任务的实例不会再生成

出错重试

勾选出错重试,当本任务运行失败时,会进行自动重试,每次间隔2分钟,可配置重试1次至5次,默认重试3次。

建议对重点任务配置重试,例如如下几种场景:

  • 数据量较大的同步任务,或运行时间较长的同步任务

  • 某些重要性较高的任务

  • 某些资源消耗比较大的任务

冻结任务

如果需要让某个任务停止运行一段时间,可以在「任务开发」模块打开某任务,在右侧「调度依赖」面板中勾选「冻结」,表示此任务进入冻结状态

  • 处于冻结状态的任务,其周期实例依然会生成,但不会运行

  • 对于存在依赖关系的多个任务,如果将上游任务A冻结,则下游任务B也会进入 冻结 状态,B任务的实例也会产生,但不会运行,在B任务的执行日志中会打印出是由于A任务被冻结才没有运行的

  • 冻结是立即生效的,冻结状态的任务,生成的实例不会立即进入冻结状态,会首先进入等待提交状态,到达计划时间后,无论上游任务的状态怎样,会立即进入冻结状态,按此逻辑,若任务实例的计划时间还未到达,任务解冻后可以正常运行

  • 已经进入冻结状态的实例无法解冻,若需要这些实例执行,必须先对任务解冻,解冻后再对实例进行「重跑」

对冻结状态的任务执行补数据,补数据实例会正常运行

自动跳过

由于小时/分钟任务的调度频率很高,且偶尔会存在执行时间过长的情况,为节约计算资源,让任务尽快「追赶」上当前时间,离线开发支持对小时/分钟任务配置自动跳过的逻辑

假设设置分钟任务的调度周期为10分钟一次,正常需要2分钟运行完成,且分钟任务处理的是当天全天的数据,且设置了自依赖模式,在2020-05-03,任务的计划时间点分别为:

  • 2020-05-03 23:10:00 --集群发生故障,任务在23:11分启动运行,但直到23:35才运行结束

  • 2020-05-03 23:20:00 --不运行实例,直接将其状态置为「自动取消」

  • 2020-05-03 23:30:00 --不运行实例,直接将其状态置为「自动取消」

  • 2020-05-03 23:40:00 --运行23:40的实例

  • 2020-05-03 23:50:00 --无论是否跳过,一天中的最后一个实例都会运行

  • 2020-05-04 00:00:00

如上文所述,在小时、分钟任务中,如果勾选了自动跳过,则离线开发可以自动跳过已经「过期」的实例,直接运行最新的一个,即可实现最新数据的产出,当然这对任务代码、自依赖模式也有要求

自动跳过只会跳过一天中间的实例,某一天最后一个实例(上例中的23:50的实例)不会跳过,以保障当天最后一个实例产出当天全天的数据

上下游依赖

配置上下游

若某任务B必须在任务A完成后运行,则A为B的上游任务,这种依赖关系可通过如下方式配置:在「调度依赖」面板中的「任务间依赖」区域中,选择相应的租户、项目,并输入上游任务的名称,在搜索的下拉结果中选择需要依赖的上游任务。

  • 一个任务可以依赖多个上游任务,一个任务也可以被多个下游任务依赖

  • 依赖属性为非必填项,当下游任务需依赖上游任务产出数据,建议配置依赖关系

  • 上游任务失败后,下游任务不会运行,且下游任务的状态会被置为「上游失败」

离线开发支持跨租户、跨项目配置上下游依赖,仅需在依赖配置时选择对应的租户和项目

选择了目标租户后,目前可以选择租户中的任意项目,这一问题会在未来版本中修复,用户应只能选择自己所在的项目

自动推荐

对于SparkSQL任务,可自动解析用户SQL代码,并自动推荐上游任务,其基本逻辑如下:

假设A任务代码:

INSERT INTO ta
    SELECT * FROM t

假设B任务代码:

INSERT INTO tb
    SELECT * FROM ta

应该配置A为B任务的上游,则A任务已经提交的前提下,在B任务点击「自动推荐」按钮,应将在推荐列表中显示A任务

目前自动推荐仅支持SparkSQL任务,未来会扩展至其他SQL任务类型

跨周期依赖

基本配置

跨周期依赖比较典型的场景是:昨天的实例必须先执行成功,今天的实例才可以调度起来,跨周期依赖的选项有4种,结合实例来看,假设A任务每天01:00运行,分析3月2日、3日的实例,不同的跨周期依赖的效果如下:

  • 不依赖上一调度周期,无论2日的实例运行情况如何,3日的实例会正常运行

  • 自依赖,等待上一调度周期成功,才能继续运行,2日的实例必须运行成功,3日的实例才具备运行的条件,若2日的实例未处于成功状态,则3日的实例会处于「等待提交」的状态

  • 自依赖,等待上一调度周期结束,才能继续运行,与上一种情况类似,但不要求2日的实例必须成功,只需要2日的实例运行结束(成功、失败、取消、自动取消)即可

结束状态包括成功、失败、取消、自动取消
依赖属性配置的调度依赖是同周期依赖和跨周期依赖不冲突。任务A可以配置依赖属性依赖任务B,也可以配置跨周期依赖依赖B,如此任务A既依赖任务B,本周期也依赖任务B上周期。

高级配置

跨周期依赖配置中还有另外2种配置:

  • 等待下游任务的上一周期成功,才能继续运行

  • 等待下游任务的上一周期结束,才能继续运行

这2种情况使用的情况较少,主要场景是:本周期该任务是否运行,取决于下游任务上一周期的运行情况。如果下游任务的上一周期运行成功/结束,本周期的任务才能开始运行,例如:

A任务、B任务:

  • 调度周期:均为10分钟

  • A为B的上游

  • A、B的结果表是同一个,均向表t的天分区写入数据,代码如下: INSERT INTO t partition (ds = 20200303) SELECT * FROM ……

  • 当A与B任务同时运行时,会出现二者同时向同一个分区写入数据的情况(无论A、B是否配置自依赖,均会发生2个任务向同一分区写数据的情况),会造成数据错乱或任务失败,如下图所示:

依赖下游任务的上一周期 图示1

在这种场景下,需要等待B任务的上个周期实例完成运行,A任务才能启动运行,应形成如下的依赖关系:

依赖下游任务的上一周期 图示2

A任务的跨周期依赖应配置为:等待下游任务的上一周期结束/成功,才能继续运行

对小时、分钟任务等高频率调度的任务,建议将依赖设置为不依赖,或者等待XX结束,防止中间某个实例失败造成下游的大面积延误或失败

几种典型场景

天任务之间的依赖

假设A、B、C任务均为天任务,依赖关系为:A→B→C,3个任务的计划时间分别为:A(01:00)、B(03:00)、C(02:00)。在资源十分充足的条件下,会产生如下的运行情况:

  • A:01:00开始运行

  • B:03:00开始运行

  • C:在当天的天任务中寻找上游依赖,则判定依赖B任务03:00的实例,C任务会在B任务03:00运行结束后才具备运行条件,C可能会在03:10开始运行

当均为天任务时,会在当天的实例中,寻找上游任务的实例

短依赖长

以天依赖月为例,A为月任务,B、C为天任务,依赖关系为:A→B/C

3个任务的计划时间为:

  • A:每月1日,01:00

  • B:每天,01:30

  • C:每天,03:00

下面以9月5日为例:B、C任务寻找的最近的一个A任务的实例,为9月1日 01:00(计划时间)的实例,则会形成如下图的依赖关系:

短依赖长示意图1

假设3个任务的计划时间变更为:

  • A:每月25日,01:00

  • B:每天,01:30

  • C:每天,03:00

依然以9月5日为例:B、C任务寻找的最近的一个A任务的实例,为8月25日 01:00(计划时间)的实例,则会形成如下图的依赖关系:

短依赖长示意图2

长依赖短

以天依赖小时为例,A为小时任务,B、C为天任务,依赖关系为:A→B/C

3个任务的计划时间为:

  • A:每天,每隔1小时运行一次,计划时间分别为:00:00、01:00……

  • B:每天,01:00

  • C:每天,03:30

依然以9月5日为例:B、C任务寻找的最近的一个A任务的实例,则会形成如下图的依赖关系:

长依赖短示意图
当前实例寻找上游实例时,永远会去寻找一个与其计划时间相等,或之前的实例,不会去寻找未来时间的实例

月被依赖的特殊处理

当月任务被依赖时,会对月任务的实例做一次特殊处理,场景如下:

假设在9月5日新建了一个月任务A,计划时间是每月1日,并设置了2个天任务B、C作为A任务的下游,按上文的依赖判断原则,B、C任务应依赖于A任务9月1日的实例,但A任务5日才被创建,不存在1日的实例,这种场景下调度系统会做特殊处理:

A由于首月创建时间较晚,实例还不存在时,B、C任务依然可以运行

A任务可以通过补数据来生成9月1日的实例,但实例不会在补数据实例中寻找上游,仅会在周期实例中寻找上游

实例的生成

离线开发在每天22:00统一生成第二天所有需要的任务实例,基于以上设计,任务开发时需要注意任务的提交时间,这里以一个天周期调度任务A为例:

1576481042730 42679a07 f1db 41fe 82dd 75bd64b20eb7

任务A基本信息:调度周期:1天;具体调度时间:8:00;

  1. 若在1月1日21:00提交A任务(时间轴上侧),离线开发会在当天22:00产生A任务的实例,并会在1月2日8:00第一次运行

  2. 若在1月1日23:00提交A任务(时间轴下侧),由于离线开发已经在22:00产生了1月2日的所有实例,A任务在1月2日将不会运行。A任务的实例将会在1月2日22:00产生,并在1月3日第一次运行

任务优先级

调度系统支持为任务手动设置优先级,在「数据开发」模块中,任务的「环境参数」中编辑优先级参数,默认参数为:

##任务优先级, 值越小,优先级越高,范围:1-1000
job.priority=10

设置了任务优先级后,可能不容易观察到效果,原因是优先级的判断是弱于任务的计划时间和上下游依赖的,只有在大量任务同时满足了计划时间+上下游依赖的前提下(即满足提交至引擎的条件),任务会大量堆积在控制台,优先级参数才会体现较为明显的效果。

各种参数的优先级判断顺序:任务计划时间 > 任务上下游 > 任务优先级参数

其他

  • 任务被删除

如果此任务被其他任务依赖(是其他任务的上游任务),则此任务不能被删除,您需要先解除依赖关系再进行删除, 任务删除后,已生成的任务实例不会被删除,但会运行失败

  • 想在每月的最后一天计算当月数据怎么办

离线开发在配置任务调度时,配置的都是计划时间,通常的每月最后一天计算当月数据,都是指的是每月1日凌晨计算上个月整月数据,建议计划时间选择每月的1日运行即可