目录
一、前言
坦白的说,DAG Scheduler是Spark的核心实现之一,概念内涵丰富,理解复杂。
二、学习DAG Scheduler的前提知识
DAG Scheduler作为Spark 作业计算过程中的调度器,涵盖了很多知识点例如RDD的血缘关系,Stage的划分,Stage的重复计算,Spark任务的错误重试机制,Spark计算的最优地址选择等问题,这些问题都会在第二章进行描述探讨。
2.2 Job
Spark 的一个计算任务,一次action操作会触发一个Job。
2.3 Stage
在Spark的计算过程中,每一个Job都可以看成是若干个stage组合形成。需要注意的是,组合形成Job的Stage可能不尽相同。
2.4 task
在Spark的计算过程中,每一个Stage都是由task组成,task是具体执行计算任务的实体,每一个task都会被发送到计算节点上进行计算。
通过对上面内容的描述,可以在下图绘制出Job,Stage,Task之间的关系,整体上是总分总的逻辑关系。
2.5 RDD血缘
RDD的血缘(lineage)通俗的来说就是找到一个RDD从头到尾的所有父类RDD。谈及到RDD血缘,不可避免的谈到RDD的宽窄依赖。宽窄依赖是一个对初学者来说比较困惑的问题,也是一个经典的面试题。RDD的依赖通俗讲,计算出一个子RDD需要计算哪些父RDD 。下面放出一张经典的图。
对RDD窄依赖的判定,根据官方文档的释意(Base class for dependencies where each partition of the child RDD depends on a small number of partitions of the parent RDD. Narrow dependencies allow for pipelined execution),窄依赖就是子RDD的每一个分区都依赖父RDD的一些分区。这个和以前的说法有些变化,以前的说法是当父RDD的分区仅被一个子RDD的分区使用,才可以说是窄依赖。如果说父RDD的一个分区被子RDD的中不同分区依赖,那么这就是宽依赖。判断子RDD和父RDD之间的依赖是什么类型依赖的最好判断方式就是判断是否是窄依赖。
2.6 RDD的血缘和Job的Stage
RDD的血缘和Job的Stage。Stage是一个并行计算任务的集合,承担Spark Job的分布计算任务。Stage中的task都有着同样的shuffle依赖。一个DAG计算任务拆分stage的过程由调度器完成,当计算过程检测到shuffle时,就在shuffle的位置进行计算任务拆分。通俗的说,在一个Job任务里,通过shuffle进行stage的拆分,或者说把一个任务任务划分成若干段,划分的点就是shuffle发生的地方。调度器会对拆分完的stage按照逻辑拓朴图的顺序去计算。
2.7 Spark中的stage
通过上面的文章得知,stage是一个task set。在Spark程序实际运行过程中,存在两种stage:shuffle map stage、result stage。map stage的task输出是其他stage的输入。result stage的task直接计算Spark的action,就是在Spark RDD上执行一个算子。对于shuffle map stage,还需要跟踪每个输出分区所在的节点。
每个Stage都会有一个FirstJobID的属性,FirstJobID是由SparkJob提交时定义的。使用FIFO调度系统时,stage的执行顺序、重算顺序都和所属的Job顺序保持一致。
同时,出于容灾的考虑,支持stage重新计算。在这种情况下,Stage对象将跟踪多个StageInfo对象以传递给侦听器或Web UI。 最新的将可以通过latestInfo访问。
引用
【1】 http://spark.apache.org/docs/0.7.3/api/core/spark/NarrowDependency.html