浅析 Spark RDD 的依赖关系

RDD 依赖关系和血缘关系

在这里插入图片描述
说明:
调用 toDebugString 方法可以查看 RDD 保存的血缘关系

RDD 窄依赖

在这里插入图片描述
新的 RDD 的一个分区的数据依赖于旧的 RDD 一个分区的数据,这个依赖称之为 OneToOne 依赖(窄依赖)
窄依赖表示每一个父(上游)RDD 的 Partition 最多被子(下游)RDD 的一个 Partition 使用,窄依赖我们形象的比喻为独生子女

RDD 宽依赖

新的 RDD 的一个分区的数据依赖于旧的 RDD 多个分区的数据,这个依赖称之为 shuffle 依赖(宽依赖)
宽依赖表示同一个父(上游)RDD 的 Partition 被多个子(下游)RDD 的 Partition 依赖,会引起 Shuffle,总结:宽依赖我们形象的比喻为多生
在这里插入图片描述
说明:
调用 dependencies 方法可以查看 RDD 之间的依赖关系

RDD 的 阶段划分 和 任务划分在这里插入图片描述

窄依赖不涉及 shuffle,数据在同一分区,因此同一个 Task 可以完成
宽依赖涉及 shuffle,数据被打乱重新组合,因此要划分为不同阶段,由不同的 Task 完成

RDD 阶段划分

在这里插入图片描述

当 RDD 调用行动算子(collect)时,沿着RDD的依赖关系往前进行深度优先遍历,若遇到一个 Shuffle 依赖,依赖的每一个父 RDD 所有分区数据都计算完毕可以分别对应一个阶段,且都是当前阶段的父阶段,继续沿着父RDD往前遍历,若遇到一个窄依赖,则直接往前遍历,直到当前所有的依赖关系都被遍历才返回上一层,通过这个过程,最后会得到一张 DAG 。DAG 的最终阶段称之为结果阶段 (Result Stage),其余的阶段称为ShuffleMap阶段。
在这里插入图片描述
一个 shuffle 依赖会创建一个 shuffle 阶段,即阶段数 +1
阶段总数量 = shuffle 依赖(宽依赖)数量 + 1(ResultStage)
ResultStage 是整个流程的最后一个阶段

阶段划分的 Spark 核心源码

①createResultStage() 方法中,先调用 getOrCreateParentStages(),获得或创建父阶段
因为只有父阶段先执行完,才会执行当前的阶段;然后再创建 ResultStage,是最后要执行的阶段
在这里插入图片描述
②核心代码:
1)进入 getOrCreateParentStages(),调用 getShuffleDependencies() 返回值是 HashSet,存放是的依赖关系,再对每一个 shuffleDependence,调用 getOrCreateShuffleMapStage() 创建 shuffle 阶段,即一个shuffle依赖就会创建一个阶段
在这里插入图片描述
2)进入 getShuffleDependencies()
在这里插入图片描述
3)进入 getOrCreateShuffleMapStage(),调用 createShuffleMapStage(),创建 shuffle 阶段 new ShuffleMapStage
在这里插入图片描述在这里插入图片描述

RDD 任务划分

RDD 任务切分中间分为:Application,Job,Stage 和 Task
①Application:初始化一个 SparkContext,即生成一个 Application
②Job:一个 Action (行动)算子就会生成一个 Job
③Stage:Stage 等于宽依赖(ShuffleDependency)的个数 +1
④Task:一个 Stage 阶段中,最后一个 RDD 的分区个数就是 Task 的个数
注意:Application->Job->Stage->Task 每一层都是 1 对 n 的关系

任务划分的 Spark 核心源码

1)进入 submitStage(finalStage),也就是 ResultStage,由于其中包含了所有阶段,相当于把整体提交
①getMissingParentStages(),查看当前阶段有没有上一级
如果有,提交上一级,重复 submitStage() 的逻辑
如果没有,执行 submitMissingTasks
在这里插入图片描述
2)submitMissingTasks(),与任务Task划分有关
①匹配阶段 shuffleMapStage or ResultStage
②每个case中的 new Task 的个数,即为任务的个数
③Task 个数与map映射的 size 有关
④map 的 size 取决于 partitionsToCompute 的结果
在这里插入图片描述

3)partitionsToCompute 返回的结果 stage.findMissingPartitions
在这里插入图片描述
由下面源码可知,返回的 map 的 size 为 numPartitions,即分区的数量
在这里插入图片描述
总结:
①任务的数量 = 当前阶段中最后一个 RDD 的分区数量
② ShuffleMapStage → ShuffleMapTask
ResultStage → ResultTask

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spark RDD(弹性分布式数据集)的依赖机制是Spark实现容错性和高效计算的核心机制之一。 在Spark中,每个RDD都表示一个可分区、只读的数据集。RDD之间的依赖关系描述了RDD之间的转换操作,并指示了RDD如何通过转换操作从父RDD生成新的子RDDRDD依赖关系可以分为两种类型:窄依赖(Narrow Dependency)和宽依赖(Wide Dependency)。 1. 窄依赖:当一个父RDD的每个分区只被一个子RDD的一个分区所使用时,我们称之为窄依赖。在这种情况下,Spark可以高效地进行转换操作,而无需重新计算所有的数据。例如,map、filter等转换操作都属于窄依赖。窄依赖允许Spark在计算中进行更多的优化,如任务划分、数据本地性等。 2. 宽依赖:当一个父RDD的分区被多个子RDD的分区所使用时,我们称之为宽依赖。在这种情况下,Spark需要通过将数据进行洗牌(Shuffle)操作来重新组织数据,以满足子RDD的需求。例如,groupByKey、reduceByKey等转换操作都属于宽依赖。洗牌操作需要涉及数据的网络传输和排序,因此会引入额外的开销。 Spark使用DAG(有向无环图)来表示RDD之间的依赖关系。每个RDD都包含其对应的转换操作和所依赖的父RDD。当执行一个Action操作时,Spark会根据RDD之间的依赖关系动态构建执行计划,并将其转化为一系列的任务来执行。 通过依赖机制,Spark可以实现容错性,即当某个分区的数据丢失或计算失败时,可以通过依赖关系重新计算该分区的数据。同时,Spark还可以根据依赖关系进行任务划分和数据本地化等优化,以提高计算效率和性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值