Spark是如何划分物理执行计划的

Spark是如何划分物理执行计划的

Spark具体采用3个步骤来生成物理执行计划:

1.首先根据action操作顺序将应用划分为作业(job)

2.然后根据每个job的逻辑处理流程中的ShuffleDependency依赖关系,将job划分为执行阶段(stage)

3.最后在每个stage中,根据最后生成的RDD的分区个数胜场多个计算任务(task)

下面我们根据一个例子来详细解释上述步骤。

Spark是如何划分物理执行计划的_第1张图片

如上图所示,这是一个Spark程序的逻辑执行流程。根据物理执行计划的划分步骤1,我们可以划分出一个作业(job)。因为整个逻辑处理流程只有图上的Results执行了action操作。由此可得下图:

Spark是如何划分物理执行计划的_第2张图片

根据物理执行计划的划分步骤2,我们可以划分出三个stage,如下图所示:

Spark是如何划分物理执行计划的_第3张图片

上图中,省略了第一步Job的划分,主要是为了读者能看清Stage的划分。Stage按照ShuffleDependency进行划分。如果读者不知道什么是ShuffleDependency,请移步至我的另一篇文章《Spark中的宽依赖和窄依赖是什么》。

根据物理执行计划的划分步骤3,我们可以划分出每个Stage中的task。

Spark是如何划分物理执行计划的_第4张图片

上图中一条带箭头的黑色粗直线表示一个task(ps:一条直线穿过多个RDD)。细心的读者会发现,此处没有对shuffle过程划分task。原因是同一个stage内部只有窄依赖(NarrowDependency),也就是说数据计算过程中不需要进行shuffle操作,这样就可以使用“流水线”式计算来提高task的执行效率,减少内存使用量。这也是Spark可以在有限内存中处理大规模数据的原因。

还有最后一个问题值得讨论:为什么stage之间(就是上图中红色箭头部分)没有进行task划分,应该如何对stage之间的操作划分task。

对于上述问题,我们可以从图中看出,stage之间存在的依赖关系是ShuffleDependency,而ShuffleDependency是部分依赖的(如果读者不清楚什么是ShuffleDependency可以移步至《Spark中的宽依赖和窄依赖是什么》),也就是下游stage中的每个task需要从parent RDD的每个分区中获取部分数据。

ShuffleDependency的数据划分需要上游stage预先将输出数据进行划分,按照分区存放,分区个数与下游task的个数一致,这个过程被成为“Shuffle Write”。按照分区存放完成后,下游的Task将属于自己分区的数据通过网络传输获取,然后将来自上游不同分区的数据聚合在一起进行处理,这个过程被成为“Shuffle Read”。总的来说,不同Stage的Task之间通过Shuffle Write + Shuffle Read传递数据,不能单纯依靠划分Task完成所有操作。至于如何具体进行Shuffle操作,分区数据是写内存还是磁盘,如何对这些数据进行聚合,我会单独出一篇文章进行介绍。

你可能感兴趣的:(Spark,spark)