阅读本篇文章,你应该得到spark面试中的这几个问题的答案:
- job的概念,job是以什么为准划分的
- stage的概念,stage是以什么为准划分的
- task的概念,task是以什么划分的
- rdd的宽窄依赖是什么,怎么区分
1、 概念关系图
其实这几个概念的理解有个比较好的思路,从stage下手;
spark在任务调度这块,将stage作为核心概念,向下:stage是一系列task的集合;向上:多个stage构成一个job,而划分job的依据是遇到action类型的算子就划分一个job;
2、job
2.1 官方说明
简单提炼一下主要的意思:
- 调度层就是一个有向的stage依赖图调度;
- 对每一个job计算一个stage依赖DAG图并且这个图保持RDD之间的依赖,在遇到一个可以物化的输出(action算子)时就划分为一个job,保证每个job里面拥有一个最小的可执行的调度模块;
- job划分完成后,将一系列的stage作为task的集合(taskset)提交到集群上并在task任务调度下进行具体的执行;
- 一个taskset是完全独立不依赖其他的任务,并且可以在集群数据上立即执行;
这些注释更加明确的显示了job的划分依据,在整个依赖图遇到action算子就会通过submitJob方法提交一个job
2.2、代码验证
提交一个action类型的job函数:
图中红色框圈选出来的分别为函数的输入和输出:
输入包含rdd,对rdd的每一个partition执行的function,失败的位置,成功结果的操作器以及一些配置;
返回值是对于这个job的同步等待器!
3、stage
3.1、官方说明
简单提炼一下主要思想:
- 图中标注的就是stage的划分依据:spark stage是被RDD DAG图中的shuffle边界划分的,简单来说,如果你的程序中出现了shuffle,那么就会以shuffle为界限,前面的构成一个stage,shuffle后的DAG构成一个stage;
- 对于窄依赖的算子,比如map,filter会形成很多的task,这些task会放到一个stage中;
- 对于具有shuffle类型的依赖,也就是宽依赖的话,整个DAG会形成多个stage,典型的是一个写map的输出,一个读map结果并shuffle;
- 整体来看,不同stage之间是以shuffle依赖来进行连接;
3.2、代码验证
3.2.1 Stage.scala
在了解stage的具体使用之前,我们需要知道stage是什么,主要包含哪几种主要的类别?
- shuffle map stage
- result stage:具体的action算子发生的地方,分别在rdd的每一个partition里面执行compute方法
对应上面两种类型的stage,相应的也会有两种生成的方法:
- createShuffleMapStage
- createResultStage
这里不详细介绍了,想仔细了解的童鞋可以查看源码,本篇主要讲区别和面试中遇到的一些问题。
3、task
3.1、官方说明
这里官方注释的比较少,只是说明了一个主要的定义:task是在work节点上的独立单元,会在每一个机器上进行执行;
它有几个基本的属性:
- 每个partition启动一个task;
- 当有很多个小文件的时候,读取的时候也会启动很多的task;
- task是由TaskScheduler进行任务的调度的;
- 每一个TaskScheduler只会在一个spark的上下文中起作用;