Spark分布式计算原理(宽窄依赖,DAG,stage划分,shuffle过程,Spark计算引擎原理)
文章目录
1、RDD依赖
Spark中RDD的高效与DAG图有着莫大的关系,在DAG调度中需要对计算过程划分stage,而划分依据就是RDD之间的依赖关系。
Lineage:血统、遗传。RDD最重要的特性之一,保存了RDD的依赖关系;RDD实现了基于Lineage的容错机制。
1.1 依赖关系
RDD之间的依赖关系分为窄依赖(narrow dependency)和宽依赖(wide dependency,也称shuffle dependency)。
1.2 窄依赖
窄依赖:一个父RDD的分区被子RDD的一个分区使用。表现为:
-
1个子RDD的分区对应于1个父RDD的分区,比如map,filter,union等算子
-
1个子RDD的分区对应于N个父RDD的分区,比如co-partioned join
1.3 宽依赖
宽依赖:一个父RDD的分区被子RDD的多个分区使用。
- 宽依赖一般是对RDD进行groupByKey,reduceByKey,sortByKey等操作,就是对partition中的数据进行重分区(shuffle)。
1.4 宽依赖对比窄依赖
-
宽依赖对应shuffle操作,需要在运行时将同一个父RDD的分区传入到不同的子RDD分区中,不同的分区可能位于不同的节点,就可能涉及多个节点间数据传输。
-
当RDD分区丢失时,Spark会对数据进行重新计算,对于窄依赖只需重新计算一次子RDD的父RDD分区。
结论:相比于宽依赖,窄依赖对优化更有利。
2、DAG
根据RDD之间的依赖关系,形成一个DAG(有向无环图)。
DAGScheduler将DAG划分为多个Stage
- 划分依据:是否发生宽依赖(Shuffle)
- 划分规则:从后往前,遇到宽依赖切割为新的Stage
- 每个Stage由一组并行的Task组成
在Spark作业调度系统中,调度的前提是判断多个作业任务的依赖关系,这些任务之间可能存在因果的依赖关系,也就是说有些任务必须先执行,然后相关的依赖任务才能执行,但是任务之间显然不应该出现任何直接或间接的循环依赖关系,所以本质上这种关系适合用DAG表示。
3、stage划分
由于shuffle依赖必须等RDD的父RDD分区数据全部可读之后才能开始计算,因此Spark的设计是让父RDD将结果写在本地,完全写完之后,通知后面的RDD。后面的RDD则首先去读之前RDD的本地数据作为输入,然后进行运算。
由于上述特性,将shuffle依赖就必须分为两个阶段(stage)去做:
- 第1个阶段(stage)需要把结果shuffle到本地,例如reduceByKey,首先要聚合某个key的所有记录,才能进行下一步的reduce计算,这个汇聚的过程就是shuffle。
- 第二个阶段(stage)则读入数据进行处理。
3.1 为什么要写在本地
后面的RDD多个分区都要去读这个信息,如果放在内存,假如出现数据丢失,后面所有的步骤全部不能进行,违背了之前所说的需要父RDD分区的数据全部ready的原则。
同一个stage里面的task是可以并发执行的,下一个stage要等前一个stage ready(和mapReduce的reduce需要等map过程ready一脉相承)。
Spark将任务以shuffle依赖(宽依赖)为边界打散,划分多个stage,最后的结果阶段叫做resultStage,其他阶段叫shuffleMapStage,从后往前推导,依次计算。
- 1、从后面往前推理,遇到宽依赖就断开,遇到窄依赖就把当前RDD加入到该stage。
- 2、每个stage里面的task的数量是由该stage中最后一个RDD的partition的数量决定的。
- 3、最后一个stage里面的任务类型是resultTask,前面其他所有的Stage的任务类型是ShuffleMapTask。
- 4、代表当前stage的算子一定是该stage的最后一个计算步骤。
3.2 移动算子而不是移动数据
在一个Stage内部算子为何会流动(Pipeline)?首先是算子合并,也就是所谓的函数式编程的执行的时候最终进行函数的展开从而把一个Stage内部的多个算子合并成为一个大算子(其内部包含了当前Stage中所有算子对数据的计算逻辑);其次,是由于Transformation操作的Lazy特性!在具体算子交给集群的Executor计算之前首先会通过Spark Framework(DAGScheduler)进行算子的优化(基于数据本地性的Pipeline)。
4、Spark Shuffle过程
在分区之间重新分配数据
- 父RDD中同一分区中的数据按照算子要求重新进入子RDD的不同分区中。
- 中间结果写入磁盘。
- 由子RDD拉取数据,而不是由父RDD推送。
- 默认情况下,shuffle不会改变分区数量。
5、Spark计算引擎原理
- 通过RDD,创建DAG(逻辑计划)
- 为DAG生成物理查询计划
- 调度并执行task
- 分布式执行task