saprk三大数据结构之RDD的依赖关系
RDD依赖关系
(1)RDD血缘关系
相邻两个RDD的关系称之为依赖关系
多个连续的RDD依赖关系称之为血缘关系
每个RDD会保存血缘关系
RDD不保存数据
因此一旦出现报错需要从头开始读取
RDD为了提供容错性,需要将RDD间的关系保存下来
一旦出现错误就可以根据血缘关系将数据源重新读取进行计算
具体血缘关系保存路程
(2)依赖关系
新的RDD的一个分区的数据依赖于旧的RDD一个分区的数据,这个依赖称之为OneToOne依赖,又名窄依赖。指代每一个父(上游)RDD的Partition 最多被子(下游)RDD 的一个 Partition 使用, 窄依赖我们形象的比喻为独生子女。
新的RDD的一个分区的数据依赖于旧的RDD多个分区的数据,这个依赖称之为Shuffle依赖,又名宽依赖,指代同一个父(上游)RDD 的 Partition 被多个子(下游)RDD 的 Partition 依赖,会 引起 Shuffle,总结:宽依赖我们形象的比喻为多生。
当RDD中存在shuffle依赖时,阶段会自动增加一个
阶段的数量 = shuffle依赖的数量 + 1(resultstage)
ResultStage只有一个,最后需要执行的阶段
application->job->stage->task ————每一个都是1:n的关系
窄依赖(Narrow Dependency)和宽依赖(Wide Dependency)
1. 窄依赖(Narrow Dependency):
窄依赖指的是每个父RDD的分区最多只被一个子RDD的分区依赖。换句话说,每个父分区只影响一个子分区。这种依赖关系也被称为一对一依赖。窄依赖的特点包括:
- 父RDD的每个分区只被一个子RDD的分区所使用。
- 窄依赖是高效的,因为每个分区的数据无需进行全局重组。
- 窄依赖的计算可以在不同的节点上并行执行。
例子: map
、filter
等转换操作,它们属于窄依赖。
2. 宽依赖(Wide Dependency):
宽依赖指的是每个父RDD的分区可能被多个子RDD的分区依赖。这意味着每个父分区的数据需要在节点之间进行 shuffle 和重组。宽依赖的特点包括:
- 父RDD的每个分区可能被多个子RDD的分区所使用。
- 宽依赖通常涉及跨节点的数据移动和重新组织,因此开销较大。
- 宽依赖的计算可能需要等待所有父分区的数据进行全局重组。
例子: groupByKey
、reduceByKey
等操作,它们属于宽依赖,因为它们需要进行数据的分组和聚合。
RDD任务划分
任务的数量 = 当前阶段中最后一个RDD的分区数量
持久化 cache & persist
如果一个RDD需要重复使用,那么需要从头再执行来获取数据
RDD对象可以重用,但是数据无法重用,因为RDD是不留存数据的
解决方法——持久化:在交给下一位时先放入内存或文件中
cache 默认持久化的操作只能把数据保存在内存中,如果想要保存到磁盘文件要用persist
持久化操作必须在行动算子执行时完成,不然没有数据
除了重用外,持久化操作还可以再数据执行较长或数据比较重要时也可以使用持久化操作
1. 内存持久化:
通过内存持久化,Spark可以将RDD的数据存储在Executor节点的内存中,这样在后续的操作中就可以更快地访问这些数据,而不需要重新计算。内存持久化可以使用不同的存储级别,包括:
- MEMORY_ONLY: 将RDD以反序列化的对象形式存储在内存中。
- MEMORY_ONLY_SER: 将RDD以序列化的形式存储在内存中,可以减少内存占用。
- MEMORY_ONLY_2,MEMORY_ONLY_SER_2,...: 表示数据备份的副本数量,增加数据的容错性。
2. 磁盘持久化:
通过磁盘持久化,Spark可以将RDD的数据存储在Executor节点的磁盘上,以便在内存不足时能够释放内存并将数据保留在磁盘上。磁盘持久化也可以使用不同的存储级别,包括:
- DISK_ONLY: 将RDD以反序列化的对象形式存储在磁盘上。
- DISK_ONLY_SER: 将RDD以序列化的形式存储在磁盘上,可以减少磁盘占用。
- DISK_ONLY_2,DISK_ONLY_SER_2,...: 表示数据备份的副本数量,增加数据的容错性。
检查点(Checkpointing):
检查点是一种将RDD的数据写入分布式文件系统(例如HDFS)的持久化机制。检查点可以有效地切断RDD的血缘关系,避免长而复杂的血缘链。这对于容错性和优化执行计划非常重要。
checkpoint 需要落盘,需要指定检查点保存路径
检查点路径保存的文件,当作业执行完毕后,不会被删除
一般保存路径都是在分布式存储系统:HDFS中
区别
(1)cache : 将数据临时存储在内存中进行数据重用,快但数据不够安全
会在血缘关系中添加新的依赖,一旦出现问题可以重头读取数据
(2)persist : 将数据存储在磁盘文件中进行数据重用,
涉及磁盘IO,性能较低但数据安全,
若作业执行完毕,临时保存的数据文件就会丢失
(3)checkpoint : 将数据长久地保存在磁盘文件中进行数据重用
涉及磁盘IO,性能较低但数据安全,
为了保证数据安全,所以一般情况下,会独立执行作业
为了能够提高效率,一般情况下是需要和cache联合使用的
执行过程中,会切断血缘关系,重新建立新的血缘关系
因为checkpoint相当于把计算结果保存在分布式存储中,比较安全,相当于数据源变化
RDD分区器
由于有时候默认分区器无法满足我们的需求,因此我们需要自己写分区器
(1)自己用class构造分区器类,并继承Partitioner类
(2)重写方法
(3)使用partitionBy(new MyPartitioner)进行引用