![Spark大数据商业实战三部曲:内核解密、商业案例、性能调优(第2版)](https://wfqqreader-1252317822.image.myqcloud.com/cover/174/40375174/b_40375174.jpg)
3.3 RDD依赖关系
RDD依赖关系为成两种:窄依赖(Narrow Dependency)、宽依赖(Shuffle Dependency)。窄依赖表示每个父RDD中的Partition最多被子RDD的一个Partition所使用;宽依赖表示一个父RDD的Partition都会被多个子RDD的Partition所使用。
3.3.1 窄依赖解析
RDD的窄依赖(Narrow Dependency)是RDD中最常见的依赖关系,用来表示每一个父RDD中的Partition最多被子RDD的一个Partition所使用,如图3-1窄依赖关系图所示,父RDD有2~3个Partition,每一个分区都只对应子RDD的一个Partition(join with inputs co-partitioned:对数据进行基于相同Key的数值相加)。
窄依赖分为两类:第一类是一对一的依赖关系,在Spark中用OneToOneDependency来表示父RDD与子RDD的依赖关系是一对一的依赖关系,如map、filter、join with inputs co-partitioned;第二类是范围依赖关系,在Spark中用RangeDependency表示,表示父RDD与子RDD的一对一的范围内依赖关系,如union。
![](https://epubservercos.yuewen.com/A9A703/20964119708003506/epubprivate/OEBPS/Images/Figure-P72_6508.jpg?sign=1739480543-RwoccsEY6o3jXIS6varg7IlYsVWN8gag-0-d8c7a3decfc4e5c70e150295c3ac9533)
图3-1 窄依赖关系图
OneToOneDependency依赖关系的Dependency.scala的源码如下:
![](https://epubservercos.yuewen.com/A9A703/20964119708003506/epubprivate/OEBPS/Images/Figure-P72_253241.jpg?sign=1739480543-u2PPAUfN4CSzgs3edzneqZ5a9AChIqmm-0-238e9b6fbdee252a3cb23ecd0db2d479)
OneToOneDependency的getParents重写方法引入了参数partitionId,而在具体的方法中也使用了这个参数,这表明子RDD在使用getParents方法的时候,查询的是相同partitionId的内容。也就是说,子RDD仅仅依赖父RDD中相同partitionID的Partition。
Spark窄依赖中第二种依赖关系是RangeDependency。Dependency.scala的RangeDependency的源码如下:
![](https://epubservercos.yuewen.com/A9A703/20964119708003506/epubprivate/OEBPS/Images/Figure-P72_253242.jpg?sign=1739480543-Tl80O2aeKxMFWwUhjLe2xcUDVsJptNc6-0-8a26a674237d474c0efaf652c15bd72e)
RangeDependency和OneToOneDependency最大的区别是实现方法中出现了outStart、length、inStart,子RDD在通过getParents方法查询对应的Partition时,会根据这个partitionId减去插入时的开始ID,再加上它在父RDD中的位置ID,换而言之,就是将父RDD中的Partition,根据partitionId的顺序依次插入到子RDD中。
分析完Spark中的源码,下边通过两个例子来讲解从实例角度去看RDD窄依赖输出的结果。
对于OneToOneDependency,采用map操作进行实验,实验代码和结果如下:
![](https://epubservercos.yuewen.com/A9A703/20964119708003506/epubprivate/OEBPS/Images/Figure-P72_253244.jpg?sign=1739480543-8IA6CSR2c7nnJoMrJ8LfDEciwWo5ctW7-0-be9228ba91a54178a3f3085b627fffb1)
结果为200 160 140。
对于RangeDependency,采用union操作进行实验,实验代码和结果如下:
![](https://epubservercos.yuewen.com/A9A703/20964119708003506/epubprivate/OEBPS/Images/Figure-P73_253246.jpg?sign=1739480543-D8e9ZJmzz1p5oRcqVR7sjtYiTHVTBqxI-0-817f4a5d719c83e76260ba74455c98bf)
结果为spark scala hadoop SPARK SCALA HADOOP。
3.3.2 宽依赖解析
RDD的宽依赖(Shuffle Dependency)是一种会导致计算时产生Shuffle操作的RDD操作,用来表示一个父RDD的Partition都会被多个子RDD的Partition使用,如图3-2宽依赖关系图中groupByKey算子操作所示,父RDD有3个Partition,每个Partition中的数据会被子RDD中的两个Partition使用。
![](https://epubservercos.yuewen.com/A9A703/20964119708003506/epubprivate/OEBPS/Images/Figure-P73_6735.jpg?sign=1739480543-AMpmRA8xwoHcpNgwXbSuI4u9VRbsAO9U-0-9bcfc3f77cf481b018f8b3a9a6957c55)
图3-2 宽依赖关系图
宽依赖的源码位于Dependency.scala文件的ShuffleDependency方法中,newShuffleId()产生了新的shuffleId,表明宽依赖过程需要涉及shuffle操作,后续的代码表示宽依赖进行时的shuffle操作需要向shuffleManager注册信息。
Spark 2.2.1版本的Dependency.scala的ShuffleDependency的源码如下:
![](https://epubservercos.yuewen.com/A9A703/20964119708003506/epubprivate/OEBPS/Images/Figure-P73_253247.jpg?sign=1739480543-DRDbTqs8DL1oWafZZj7Om7V5S5mb8qk7-0-396bc511afb6b4a7da5eb8f8c1af20a3)
Spark 2.4.3版本的Dependency.scala源码与Spark 2.2.1版本相比具有如下特点。
上段代码中第9行后面新增加了对mapSideCombine的条件判断。
![](https://epubservercos.yuewen.com/A9A703/20964119708003506/epubprivate/OEBPS/Images/Figure-P74_253249.jpg?sign=1739480543-ax3S6jqlYjAPLClua0JJUuAtn6QCDq4k-0-1085e077b0f18fe8874df4ce2480a8cf)
Spark中宽依赖关系非常常见,其中较经典的操作为GroupByKey(将输入的key-value类型的数据进行分组,对相同key的value值进行合并,生成一个tuple2,如图3-3所示),具体代码和操作结果如下所示。输入5个tuple2类型的数据,通过运行产生3个tuple2数据。
![](https://epubservercos.yuewen.com/A9A703/20964119708003506/epubprivate/OEBPS/Images/Figure-P74_253250.jpg?sign=1739480543-7ZxTR8aV6pcPwE9ql5TCUTqZo05eHBE1-0-b4336bbcc78dc38129e6a0e639fe16a8)
操作结果如图3-3所示。
![](https://epubservercos.yuewen.com/A9A703/20964119708003506/epubprivate/OEBPS/Images/Figure-P74_7032.jpg?sign=1739480543-5hXgQmnNxvpg3l6YabfMmXQH4sE3to9o-0-da9b00aa77b4e3a12a0a11739e00fa04)
图3-3 GroupByKey结果