spark中RDD 的依赖关系

本文介绍了Spark中RDD的依赖关系,包括窄依赖和宽依赖,窄依赖指父RDD分区最多被子RDD一个分区使用,宽依赖则是多个子RDD分区依赖同一父RDD分区。还提到RDD的Lineage用于恢复丢失分区。此外,阐述了RDD的缓存机制,包括缓存方式、存储级别及容错机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

spark中RDD 的依赖关系
1、RDD 的依赖
RDD 和它依赖的父RDD 的关系有两种不同的类型, 即窄依赖( narrowdependency)和宽依赖(wide dependency)。
在这里插入图片描述
2、窄依赖
窄依赖指的是每一个父RDD 的Partition 最多被子RDD 的一个Partition 使用
总结:窄依赖我们形象的比喻为独生子女
3、宽依赖
宽依赖指的是多个子RDD 的Partition 会依赖同一个父RDD 的Partition
总结:宽依赖我们形象的比喻为超生
4、Lineage(血统)
RDD 只支持粗粒度转换,即只记录单个块上执行的单个操作。将创建RDD的一系列Lineage(即血统)记录下来,以便恢复丢失的分区。RDD 的Lineage会记录RDD 的元数据信息和转换行为,当该RDD 的部分分区数据丢失时,它可以根据这些信息来重新运算和恢复丢失的数据分区。
5、RDD 的缓存
Spark 速度非常快的原因之一,就是在不同操作中可以在内存中持久化或者缓存数据集。当持久化某个RDD 后,每一个节点都将把计算分区结果保存在内存中,对此RDD 或衍生出的RDD 进行的其他动作中重用。这使得后续的动作变得更加迅速。RDD 相关的持久化和缓存,是Spark 最重要的特征之一。可以说,缓存是Spark 构建迭代式算法和快速交互式查询的关键。
RDD 缓存方式
RDD 通过persist 方法或cache 方法可以将前面的计算结果缓存,但是并不是这两个方法被调用时立即缓存,而是触发后面的action 时,该RDD 将会被缓存在计算节点的内存中,并供后面重用。
在这里插入图片描述
通过查看源码发现cache 最终也是调用了persist 方法,默认的存储级别都是仅在内存存储一份, Spark 的存储级别还有好多种, 存储级别在objectStorageLevel 中定义的。
在这里插入图片描述
缓存有可能丢失,或者存储于内存的数据由于内存不足而被删除,RDD 的缓存容错机制保证了即使缓存丢失也能保证计算的正确执行。通过基于RDD 的一系列转换,丢失的数据会被重算,由于RDD 的各个Partition 是相对独立的,因此只需要计算丢失的部分即可,并不需要重算全部Partition。

### Apache SparkRDD 的使用与原理 #### 1. RDD 基本概念 RDD(Resilient Distributed Dataset,弹性分布式数据集)是 Spark 的核心抽象之一。它表示一个不可变的、分区化的集合,可以在集群节点之间分布存储[^3]。RDD 支持两种主要的操作:转换(Transformation)行动(Action)。这些操作使得开发者能够高效地处理大规模的数据。 #### 2. RDD 特性 以下是 RDD 的一些重要特性: - **只读性**:一旦创建,RDD 数据不能被修改。 - **可分区化**:RDD 可以划分为多个分区,分布在不同的节点上进行并行计算。 - **容错性**:通过记录血缘关系(Lineage),即使某些节点失败,也可以重新计算丢失的部分。 - **持久化支持**:可以选择将 RDD 缓存到内存或磁盘中,从而提高重复使用的效率。 #### 3. RDD 创建方式 RDD 主要可以通过以下几种方式进行创建: - **从外部数据源加载**:例如 HDFS 文件或其他分布式文件系统中的数据。 - **基于已有的 Scala/Python 集合对象**:可以直接将本地集合转化为 RDD。 - **通过对现有 RDD 进行转换**:通过 Transformation 操作生成新的 RDD。 下面是一段简单的代码示例展示如何创建 RDD: ```scala // 导入必要的库 import org.apache.spark.{SparkConf, SparkContext} // 初始化 Spark 上下文 val conf = new SparkConf().setAppName("Example").setMaster("local") val sc = new SparkContext(conf) // 从集合创建 RDD val data = List(1, 2, 3, 4, 5) val rddFromList = sc.parallelize(data) // 从文件创建 RDD val fileRdd = sc.textFile("path/to/file.txt") // 执行 Action 查看结果 rddFromList.collect().foreach(println) fileRdd.foreach(println) ``` 上述代码展示了如何从列表平面文件分别创建 RDD 并打印其内容[^2]。 #### 4. 转换与行动 ##### 转换(Transformations) 转换是一种返回新 RDD 的懒惰操作。常见的转换包括 `map`、`filter` `reduceByKey` 等。它们不会立即执行,而是构建 DAG 图等待后续触发。 例子如下: ```scala // 使用 map 对每个元素平方 val squaredRdd = rddFromList.map(x => x * x) // 使用 filter 筛选出偶数 val evenNumbers = rddFromList.filter(_ % 2 == 0) ``` ##### 行动(Actions) 行动会触发改写后的实际计算过程,并返回最终结果或者将数据保存至外部存储。典型的行动有 `collect`、`count` `saveAsTextFile`。 例子如下: ```scala // 计算总数量 val countResult = rddFromList.count() // 将结果保存为文本文件 evenNumbers.saveAsTextFile("output/even_numbers") ``` #### 5. 依赖窄依赖Spark 的内部机制中,RDD依赖关系决定了 Stage 的划分。如果两个 RDD 存在依赖,则意味着需要 shuffle 操作;而窄依赖则不需要 shuffle,因此性能更优[^4]。 #### 6. 总结 RDDSpark 处理大数据的基础组件,具有丰富的特性强大的灵活性。尽管现代版本逐渐推广 DataFrame DataSet API,但对于底层控制需求较高的场景,RDD 仍然是不可或缺的选择。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值