Spark笔记

1.RDD依赖关系与stage

RDD依赖关系分为以下两种:窄依赖和宽依赖。

2.1窄依赖与宽依赖

2.1.1窄依赖

窄依赖就是指父RDD的每个分区只被一个子RDD分区使用,子RDD分区通常只对应常数个父RDD分区。窄依赖分为以下两类:

  • 1个子RDD的分区对应于1个父RDD的分区,比如map,filter,union等算子
  • 1个子RDD的分区对应于N个父RDD的分区,比如co-partioned join

2.1.2宽依赖(Shuffle依赖)

宽依赖就是指父RDD的每个分区都有可能被多个子RDD分区使用,子RDD分区通常对应父RDD所有分区。宽依赖分为以下两类:

  • 1个父RDD对应非全部多个子RDD分区,比如groupByKey,reduceByKey,sortByKey
  • 1个父RDD对应所有子RDD分区,比如未经协同划分的join
    在这里插入图片描述

2.1.3宽窄依赖的区别

1.计算方式
宽依赖往往对应着shuffle操作,需要在运行过程中将同一个父RDD的分区传入到不同的子RDD分区中,中间可能涉及到多个节点之间的数据传输;
而窄依赖的每个父RDD的分区只会传入到一个子RDD分区中,通常可以在一个节点内就可以完成了。

2.重算方式
当RDD分区丢失时(某个节点故障),spark会对数据进行重算。
对于窄依赖,由于父RDD的一个分区只对应一个子RDD分区,这样只需要重算和子RDD分区对应的父RDD分区即可,所以这个重算对数据的利用率是100%的;
对于宽依赖,重算的父RDD分区对应多个子RDD分区,这样实际上父RDD 中只有一部分的数据是被用于恢复这个丢失的子RDD分区的,另一部分对应子RDD的其它未丢失分区,这就造成了多余的计算;更一般的,宽依赖中子RDD分区通常来自多个父RDD分区,极端情况下,所有的父RDD分区都要进行重新计算。
如下图所示,b1分区丢失,则需要重新计算a1,a2和a3,这就产生了冗余计算(a1,a2,a3中对应b2的数据)。
在这里插入图片描述

2.2 stage划分

2.2.1 stage概念

Spark任务会根据RDD之间的依赖关系,形成一个DAG有向无环图,DAG会提交给DAGScheduler,DAGScheduler会把DAG划分相互依赖的多个stage,划分stage的依据就是RDD之间的宽窄依赖。遇到宽依赖就划分stage,每个stage包含一个或多个task任务。然后将这些task以taskSet的形式提交给TaskScheduler运行。 stage是由一组并行的task组成。

2.2.2 为什么要划分stage

(1) 窄依赖(narrow dependencies)
可以支持在同一个集群Executor上,以pipeline管道形式顺序执行多条命令,例如在执行了map后,紧接着执行filter。分区内的计算收敛,不需要依赖所有分区的数据,可以并行地在不同节点进行计算。所以它的失败恢复也更有效,因为它只需要重新计算丢失的parent partition即可
(2)宽依赖(shuffle dependencies)
则需要所有的父分区都是可用的,必须等RDD的parent partition数据全部ready之后才能开始计算,可能还需要调用类似MapReduce之类的操作进行跨节点传递。从失败恢复的角度看,shuffle dependencies 牵涉RDD各级的多个parent partition。

划分完stage之后,同一个stage里面只有窄依赖,没有宽依赖,可以实现流水线计算,stage中的每一个分区对应一个task,同一个stage中就有很多可以并行运行的task

2.2.3 stage分为两个阶段

由于shuffle依赖必须等RDD的父RDD分区数据全部可读之后才能开始计算,因此Spark的设计是让父RDD将结果写在本地,完全写完之后,通知后面的RDD。后面的RDD则首先去读之前RDD的本地数据作为输入,然后进行运算。
由于上述特性,讲shuffle依赖就必须分为两个阶段(stage)去做:

  • 第1个阶段(stage)
    需要把结果shuffle到本地,例如reduceByKey,首先要聚合某个key的所有记录,才能进行下一步的reduce计算,这个汇聚的过程就是shuffle。
  • 第二个阶段(stage)
    则读入数据进行处理。

为什么要写在本地?
后面的RDD多个分区都要去读这个信息,如果放到内存,假如出现数据丢失,后面所有的步骤全部不能进行,违背了之前所说的需要父RDD分区数据全部ready的原则。

2.2.4 如何划分stage

同一个stage里面的task是可以并发执行的,下一个stage要等前一个stage ready(和map reduce的reduce需要等map过程ready一脉相承)。
Spark 将任务以 shuffle 依赖(宽依赖)为边界打散,划分多个 Stage. 最后的结果阶段叫做 ResultStage, 其它阶段叫 ShuffleMapStage, 从后往前推导,依将计算。Spark 将任务以 shuffle 依赖(宽依赖)为边界打散,划分多个 Stage. 最后的结果阶段叫做 ResultStage, 其它阶段叫 ShuffleMapStage, 从后往前推导,依将计算。

如下图所示:从G往前推,BG依赖于B和F。
BG是窄依赖,不用划分stage。B依赖于A,且A和B是宽依赖。所以A到B需要划分一个stage
FG之间是宽依赖,所有F到G需要划分一个stage,F依赖于D和E,但都是窄依赖,不划分stage,D依赖于C,窄依赖,不需要划分stage。

在这里插入图片描述

参考
Spark宽依赖与窄依赖
Spark宽依赖和窄依赖深度剖析
Spark --【宽依赖和窄依赖】

2.shuflle

了解了宽窄依赖后我们再具体看一下宽依赖的shuflle。

在Spark或Hadoop MapReduce的分布式计算框架中,数据被按照key分成一块一块的分区,打散分布在集群中各个节点的物理存储或内存空间中,每个计算任务一次处理一个分区,但map端和reduce端的计算任务并非按照一种方式对相同的分区进行计算,例如,当需要对数据进行排序时,就需要将key相同的数据分布到同一个分区中,原分区的数据需要被打乱重组,这个按照一定的规则对数据重新分区的过程就是Shuffle(洗牌)。

下图是一个计算,根据宽窄依赖已经划分了stage。
在这里插入图片描述
将对应的 RDD 标注上去后:
在这里插入图片描述
对于这一过程,我们分析其中的 Shuffle:
在这里插入图片描述
这其中就涉及到 Shuffle 过程,前一个 Stage 的 ShuffleMapTask 进行 Shuffle Write, 把数据存储在 BlockManager 上面, 并且把数据位置元信息上报到 Driver 的 MapOutTrack 组件中, 下一个 Stage 根据数据位置元信息, 进行 Shuffle Read, 拉取上个 Stage 的输出数据。

触发Shuffle的操作
在这里插入图片描述

参考
Spark Shuffle的技术演进
Spark Shuffle 详解

https://juejin.im/post/6844904098047721486

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值