Spark的任务调度学习

背景

Spark的调度依次是Application调度、Job调度、Stage调度和Task调度,其中在Spark On Yarn下,Application调度是ResourceManager的工作,Application级别资源的调度是Yarn来分配的,这在《Spark下Yarn-Cluster和Yarn-Client的区别中》做了介绍。本文所记录的Spark的任务调度是在Application已经取得集群资源的前提下进行的,开始于SparkContext,记录了Job、Stage和Task调度。本文的理解基于Yarn模式。

任务调度流程

总的任务调度流程如下图所示,这与张安站《Spark技术内幕》P45的理解不同,任务调度我觉得应该是在Driver而不是在Client
任务调度模块涉及的最重要的三个类:

  • org.apache.spark.scheduler.DAGScheduler
    DAGScheduler的工作开始于SparkContext创建之后,主要是分析用户已经提交的应用,并根据计算任务的依赖关系建立DAG,然后将DAG划分为不同的stage,也就是一组task。DAG在不同的资源管理框架下的实现是相同的。
  • org.apache.spark.scheduler.TaskScheduler
    DAGScheduler将这组task划分完毕后,会将这组task提交到TaskSchedule,TaskScheduler从DAGScheduler接收不同stage的task,并且向集群提交这些task,为每个task分配计算资源(Executor)。
  • org.apache.spark.scheduler.SchedulerBackend
    SchedulerBackend作用是取得Application的计算资源交由TaskScheduler,并且在分配的Executor上启动Task,完成计算的调度过程。

TaskScheduler、DAGScheduler是在SparkContext创建的时候跟着就创建的。DAGScheduler持有TaskScheduler对象、MapOutputTrackerMaster和BlockManagerMaster、SparkEnv对象。其中MapOutputTrackerMaster存储shuffle的元数据信息,BlockManagerMaster存储集群block的元数据信息,SparkEnv包含了一个运行时节点所需的所有的环境信息。
Spark任务调度逻辑图
根据上图可以看到具体的Spark任务调度过程:
(1)白色部分:Spark遇到Action生成一个Job,SparkContext.runJob()提交这个Job到DAGScheduler;
(2)DAGScheduler会调用自己的runJob()方法对Job进行处理,首先会为这个Job生成一个JobID和JobWaiter来监听Job的执行情况;
然后DAGScheduler调用handleJobSubmitted()方法会根据依赖关系递归进行Job的Stage划分,所以会首先创建finalStage;
递归提交未计算的parent Stage,只有所有的parent Stage都计算完成后,才能提交它;
最后DAGScheduler调用submitMissingTasks()向TaskScheduler提交Task,它提交的Tasks是对应于需要计算的Partition,不需要计算的Partition说明已经有了缓存,把这些task封装到TaskSet,提交给TaskScheduler。
至此,DAGScheduler完成了它的使命,然后它会等待TaskScheduler最终向集群提交这些Task,(JobWaiter会)监听这些task的状态。
(3)DAGScheduler完成了对Stage的划分之后,会按照顺序逐个将Stage提交到TaskScheduler上,开始task级别的调度;
将本Stage的TaskSet加入到一个TaskSetManager里面,TaskSetManager会根据数据的就近原则分配计算资源,监控task的执行状态并采取必要的措施,比如失败重试和慢任务的推测执行,TaskSetManager首先会根据task失败的原因来采取不同的动作;
然后SchedulerBackend与ResourceManager交互,取得Application分配到的资源,并交由TaskScheduler;
TaskScheduler的resourceOffers()方法为每个Task具体分配资源,它的输入是Executor的列表(说明这个时候Executors早已经被启动了),输出是TaskDescription的二维数组(包含TaskID、Executor ID、 Task执行环境的以来信息等),实现对task的封装;
最后SchedulerBackend在Executor上启动task。
(4)TaskSetManager会对task的执行结果做出反应,JobWaiter会监听整个Job的执行情况;
当有task执行失败时,TaskSetManager会启动处理任务执行失败的容错机制,根据失败原因采取不同的动作;
当一个Stage所有的task都执行成功后,这个Stage就执行成功了,就可以提交新的Stages;
如果这个Stage是finalStage,说明这个Job也已经成功结束了。

我可能是个坑

里面很多地方都是自己的理解,“推测执行”,哈哈。。。对张安站《Spark技术内幕》提出的质疑也是自己的理解,所以我可能还是一个坑。。。

Reference

  1. 《Spark技术内幕》
  2. 《Spark大数据处理-技术、应用与性能优化》
阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/BlockheadLS/article/details/53497260
文章标签: 任务调度 spark
个人分类: Spark学习之路
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭