Spark逻辑图的执行

1、先表结论,如下图所示

Spark逻辑图的执行


2.文字说明

  • driver 有多少个 action(),就会生成多少个job。从后往前看,RDD有多少个partition(可以在程序中指定)就会有多少个task,但是一个开始有多少个task,则是由原始数据决定的。
  • 如果 stage 是 ShuffleMapStage,那么 new 出来与该 stage 最后一个 RDD 的 partition 数相同的ShuffleMapTasks。如果 stage 是 ResultStage,那么 new 出来与 stage 最后一个 RDD 的 partition 个数相同的ResultTasks。
  • 每个 stage 里面 task 的数目由该 stage 最后一个 RDD 中的 partition 个数决定。
  • Pipeline思想:数据用的时候再算,而且数据是流到要计算的位置的。Result产生的地方的就是要计算的位置,要确定“需要计算的数据”,我们可以从后往前推,需要哪个 partition 就计算哪个 partition,如果 partition 里面没有数据,就继续向前推,形成 computing chain。这样推下去,结果就是:需要首先计算出每个 stage 最左边的 RDD 中的某些 partition。
  • 对于没有 parent stage 的 stage,该 stage 最左边的 RDD 是可以立即计算的。对于有 parent stage 的 stage,先等着所有 parent stages 中 final RDD 中数据计算好,然后经过 shuffle 后,问题就又回到了计算 “没有 parent stage 的 stage”。
  • 整个 computing chain 根据数据依赖关系自后向前建立,遇到 ShuffleDependency 后形成 stage。在每个stage 中,每个 RDD 中的 compute() 调用 parentRDD.iter() 来将 parent RDDs 中的 records 一个个 fetch 过来。computing chain从后到前建立,而实际计算出的数据从前到后流动,而且计算出的第一个 record 流动到不能再流动后,再计算下一个record。这样,虽然是要计算后续 RDD 的 partition 中的 records,但并不是要求当前 RDD 的 partition 中所有 records 计算得到后再整体向后流动。
  • 代码实现:每个 RDD 包含的 getDependency() 负责确立 RDD 的数据依赖,compute() 方法负责接收 parent RDDs或者 data block 流入的 records,进行计算,然后输出 record。经常可以在 RDD 中看到这样的代码 firstParent[T].iterator(split, context).map(f) 。firstParent 表示该 RDD 依赖的第一个 parent RDD,iterator() 表示parentRDD 中的 records 是一个一个流入该 RDD 的,map(f) 表示每流入一个 recod 就对其进行 f(record) 操作,输出 record。为了统一接口,这段 compute() 仍然返回一个 iterator,来迭代 map(f) 输出的 records。