Spark --【宽依赖和窄依赖】

1.前言

《上一节Spark DAG概述》Spark中RDD的高效与DAG图有着莫大的关系,在DAG调度中须要对计算过程划分stage,
暴力的理解就是stage的划分是按照有没有涉及到shuffle来划分的,没涉及的shuffle的都划分在一个stage里面,
这种划分依据就是RDD之间的依赖关系。针对不一样的转换函数,RDD之间的依赖关系分类窄依赖(narrow dependency)
和宽依赖(wide dependency, 也称 shuffle dependency)

2.定义

1.窄依赖是指父RDD的每一个分区只被子RDD的一个分区所使用,子RDD分区一般对应常数个父RDD分区(O(1),与数据规模无关)
2.相应的,宽依赖是指父RDD的每一个分区均可能被多个子RDD分区所使用,子RDD分区一般对应全部的父RDD分区(O(n),与数据规模有关)
3.宽依赖和窄依赖关系图:
     

3.为何要有宽窄依赖?

1.前面已经说过了stage划分的一个很重要的缘由就是有没有涉及到shuffle,若是没涉及到的被划分到一个stage里面。
2.没有涉及shuffle的任务直接运行就能够,这个也就是常提到的pipeline。这种面向的就是窄依赖。
    √ 每一个分区里的数据都被加载到机器的内存里,咱们逐一的调用 map, filter, map 函数到这些分区里,Job 就很好的完成。
    √ 更重要的是,因为数据没有转移到别的机器,咱们避免了 Network IO 或者 Disk IO. 
    惟一的任务就是把 map / filter 的运行环境搬到这些机器上运行,这对现代计算机来讲,overhead 几乎能够忽略不计。
    √ 这种把多个操做合并到一块儿,在数据上一口气运行的方法在 Spark 里叫 pipeline 
    (其实 pipeline 被普遍应用的不少领域,好比 CPU)。
    这时候不一样就出现了:只有 narrow transformation 才能够进行 pipleline 操做。
    对于 wide transformation, RDD 转换须要不少分区运算,包括数据在机器间搬动,因此失去了 pipeline 的前提。
    √ 总结起来一句话:数据和算是否在一块儿,计算的性能是不同的,为了区分,就有了宽依赖和窄依赖。
3.一提到shuffle若是以前对mapreduce有过了解的人都知道,这个对分布式影响巨大,
spark也是一步步演变过来的,如今能够说spark2.x以上的shuffle能够认为和经典的mapreduce的shuffle同样了,到如今能够
说spark彻底比mr有优点了。这以前,在一些场景下spark仍是比不过mr的。(看这篇《Spark 与MapReduce 资源调度方面的简单对比》)

4.宽窄依赖如何优化?----得想一想

4.窄依赖对优化的帮助

1.宽依赖每每对应着shuffle操做,须要在运行过程当中将同一个父RDD的分区传入到不一样的子RDD分区中,中间可能涉及到多个节点之间的
  数据传输;而窄依赖的每一个父RDD的分区只会传入到一个子RDD分区中,一般能够在一个节点内就能够完成了。
2.当RDD分区丢失时(某个节点故障),spark会对数据进行重算。
    1).对于窄依赖,因为父RDD的一个分区只对应一个子RDD分区,这样只须要重算和子RDD分区对应的父RDD分区便可,
    因此这个重算对数据的利用率是100%的;
	2).对于宽依赖,重算的父RDD分区对应多个子RDD分区,这样实际上父RDD 中只有一部分的数据是被用于恢复这个丢失的子RDD
    分区的,另外一部分对应子RDD的其它未丢失分区,这就形成了多余的计算;更通常的,宽依赖中子RDD分区一般来自多个父RDD
    分区,极端状况下,全部的父RDD分区都要进行从新计算。 
3.以下图所示,b1分区丢失,则须要从新计算a1,a2和a3,这就产生了冗余计算(a1,a2,a3中对应b2的数据)
    
区分这两种依赖颇有用。首先,窄依赖容许在一个集群节点上以流水线的方式(pipeline)计算全部父分区。
例如,逐个元素地执行map、而后filter操做;
而宽依赖则须要首先计算好全部父分区数据,而后在节点之间进行Shuffle,这与MapReduce相似。
第二,窄依赖可以更有效地进行失效节点的恢复,即只需从新计算丢失RDD分区的父分区,并且不一样节点之间能够并行计算;
而对于一个宽依赖关系的Lineage图,单个节点失效可能致使这个RDD的全部祖先丢失部分分区,于是须要总体从新计算。

窄依赖中每一个子RDD可能对应多个父RDD,当子RDD丢失时会致使多个父RDD进行从新计算,因此窄依赖不如宽依赖有优点。

而实际上应该深刻到分区级别去看待这个问题,并且重算的效用也不在于算的多少,而在于有多少是冗余的计算。
窄依赖中须要重算的都是必须的,因此重算不冗余

窄依赖的函数有:map, filter, union, join(父RDD是hash-partitioned ), mapPartitions, mapValues 
宽依赖的函数有:groupByKey, join(父RDD不是hash-partitioned ), partitionBy
相关文章
相关标签/搜索