spark是基于MApreduce的一个并行计算框架。
Spark中数据的组织通过RDD方式完成。
RDD可以理解成为一组数据加上对数据的操作。
不可以更改的,但是RDD可以从一个RDD转换成为另外的一个RDD。
窄依赖就类似于图上面的这种,一个前面的RDD中的partition只会被后面的一个RDD的partition所依赖。
宽依赖就类似于上面的这种,一个前面的partition会后面的至少两个partition所依赖。
那么划分宽窄依赖的好处是啥?(后面将会讲到)。
逻辑完全一致,不同的是作用于不同的数据集。
stage是任务是否向前推进的基本单位。
宽依赖是spark划分不同的stage的依据是通过宽依赖来进行划分的。
同一个stage中的task是可以并行执行的,看下图中的stage2,task1和task2之间,因为任务只依赖于前面的RDD中指定的partition,所以,task1和task2可以并行的执行。
时机是在任务执行前。
那么具体的划分stage的方法是什么呢?
大体的步骤是先生成该RDD的parent 的stage,然后生成该RDD的stage。例如:
这样好处就是,一个stage中的task是可以并行计算的,例如task1,task2,task3,都不需要外部干预就可以并行计算了。(这是我想的,具体实现是不是这样的还需要研究研究),但是Resulttask3、4、5的输入是来自于shuffle后的输出,从这点考虑,划分stage是便于管理咯?因为spark事先没有数据的元数据信息,所以其shuffle后才知道哪些数据应该生成哪些task上面扔。
划分是从最后一个RDD,也就是G开始,可以看出,BG属于窄依赖,那么划分到一个stage中。GF是宽依赖,所以,划分到不同的stage中。
过来一条任务,spark会对它生成具体的DAG。生成的DAG中的最后一个RDD的划分任务的开始。
凡是和最后一个RDD是属于窄依赖的,被划分到和最后一个RDD的同一个stage中。
如果是宽依赖,那么就生成一个parent stage:
首先,这个正在划分stage的RDD会做判断:
---->parent stage 没有生成
:生成新的stage
----->parent stage已经生成
元数据信息在RDD中,
如果某个partition的结果丢失了,也会记录这个丢失的结果。
这个结果会储存在Driver端,其他的task可以通过查询来使用task的结果。
当把stage划分好了以后,我们就要开始生成任务并执行了
任务的提交(或者就叫做的执行完毕后的提交)的规则是,一个stage的所以的parent stage都提交了后,这个stage中完成,这个stage才能够被提交。
所以,代码中是按照递归的方式来进行任务的推进的 ,如下:
SubmitStage(stage){
//这个我想的是,注册JobId用的
jobId = activeJobForStage( stage )
missing = getMissingParentStage( stage ) // 获取到parent的中的哪些stage还没有完成的
if(mssing == Nil){
//向TaskScheduler提交task/ResultTask,然后进行计算或者是读缓存
//先判断哪些partition是需哟啊计算的,那些需要计算的partition会生成一个task,然后提交给taskScheduler
submitMissgingTasks( stage , jobId);
}else {
for( parent <- missing){ // 如果还有parent的stage是没有运算好的,那么就递归的提交这些stage
SubmitStage(stage)
}
watingSages += stage
}
}
未完待续..