首页 > 大数据 > > spark任务调度原理
Spark的作业和任务调度系统是核心,它能够有效的进行调度的原因是对任务的划分DAG和容错,使得它对底层到顶层的各个模块之间的调用和处理显得游刃有余。
Spark的作业调度主要是基于RDD的一系列操作构成一个作业,然后在Executor中执行,其中操作分为转换和行动操作,对于转换操作的计算是Lazy级别的,只有行动操作才能触发作业的提交。

如何划分调度阶段
Spark的调度阶段的划分是有DAGScheduler实现的,DAGScheduler会由最后一个RDD出发,使用广度优先遍历整个依赖树,从而划分调度阶段。
调度阶段的划分依据是以操作是否为宽依赖(也就是是否有shuffle)进行的,如果某个RDD的操作是shuffle时,以该shuffle为界限划分前后两个阶段。
例如:

1、从最后一个rddG判断是否存在Shuffle操作,有Join,所以为宽依赖,进而拆分出两个调度阶段ResultStage3和上一层调度;
2、ResultStage3找到了两个rddB 和rddF,由rddB往前找,找到最开始的rddA,且操作为窄依赖,所以rddA和rddB之间的转换为一个调度阶段Stage0.
3、rddF往前找,找到rddE,是窄依赖,在往前找,出现了groupBy为宽依赖,所以这个地方也要划分为两个调度阶段,划分rddE到rddF为一个调度阶段,rddE之前的rddD为一个阶段。
4、rddD,在往前rddC为窄依赖,所以划分为一个调度阶段。
所以这个任务最后由rddG遍历划分为以上4个调度阶段,提交后然后反过来执行。当入口的调度阶段执行完后,相继提交后续的阶段,在判断该调度阶段依赖的父调度阶段的结果是否可用,如果都可用,则提交该调度阶段。如果执行失败,则重新提交该调度阶段。
如何调度
例如:
上面的调度阶段划分完成后,实际的调度顺序

1、获取最后一个调度阶段ResultStage3,通过submitStage提交运行该调度阶段。
2、判断该调度存在两个父调度ShuffleMapStage0和ShuffleMapStage2,所以不能立即执行,将ResultStage3加入等待执行调度阶段列表waitingStages中。
3、递归调用submitStage,知道ShuffleMapStage0不存在父调度阶段,ShuffleMapStage2存在父调度阶段ShuffleMapStage1,所以ShuffleMapStage2加入等待执行调度列表,ShuffleMapStage1不存在父调度阶段,所以ShuffleMapStage0和ShuffleMapStage1作为第一次调度使用submitMissingTasks提交运行。
4、Executor任务执行完后,发送消息,DAGScheduler稽查调度阶段运行情况,如果完成,举行提交调度阶段运行,如果失败,重新提交该调度阶段,直到所有的调度阶段执行完成。
任务执行
当调度阶段提交运行后,DAGScheduler的submitMissingTasks方法中,会根据调度阶段的Partition个数来拆分对应个数的任务,这些任务组成任务集提交到TaskScheduler进行处理,作业中的任务调度ShuffleMapStage会生成ShuffleMapTask,作业的最后调度阶段ResultStage生成ResultTask。
对于ShuffleMapTask,计算结果会写到BlockManager中,返回DAGScheduler一个MapStatus对象,存储BlockManager的基本信息,这些存储信息将会成为下一个阶段任务需要获取的输入数据依据。
对于ResultTask,返回最终的func函数的计算结果。
FIFO调度策略
调度过程中,Master先启动等待列表中应用程序的Driver,并尽可能的分散在集群的Worker节点上(充分利用集群资源,而且有利于数据的本地性),根据集群的内存和CPU使用情况,对等待运行的应用程序进行资源分配,分配算法上根据先来先分配,先分配的任务尽可能的获取满足条件的资源,后分配的任务在剩余资源中再次筛选,如果没有合适的资源只能等待:
FAIR调度策略
调度过程中,先获取调度的饥饿程度,饥饿程度为正在运行的任务是否小于最小任务,如果是,表示调度处理处于饥饿程度。获取饥饿程度后比较:
数据的计算尽可能在数据所在的节点中运行,这样可以减少不必要的网络传输,毕竟移动计算比移动数据的代价要小很多。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/31509949/viewspace-3157710/ ,如需转载,请注明出处,否则将追究法律责任。