Spark 中 RDD 的依赖关系

本文深入探讨了Spark中的RDD血缘关系,详细解释了RDD的依赖、窄依赖和宽依赖概念,并阐述了如何根据依赖关系进行阶段划分和任务划分。了解这些内容对于优化Spark应用性能至关重要。

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

一、RDD 血缘关系

RDD 只支持粗粒度转换,即在大量记录上执行的单个操作。将创建 RDD 的一系列 Lineage(血统)记录下来,以便恢复丢失的分区。RDD 的 Lineage 会记录 RDD 的元数据信息和转换行为,当该 RDD 的部分分区数据丢失时,它可以根据这些信息来重新运算和恢复丢失的数据分区。

通过 rdd.toDebugString 方法可以看到 RDD 的血缘关系:

package spark.core.dependent

import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.rdd.RDD

/**
 * RDD 血缘关系
 */
object Spark_RDD_Operator_Dependent_Study1 {
  def main(args: Array[String]): Unit = {
    val sparkConf = new SparkConf().
      setMaster("local[*]").
      set("spark.driver.host", "localhost").
      setAppName("rdd")
    val sc = new SparkContext(sparkConf)

    val fileRDD: RDD[String] = sc.textFile("input/word.txt")
    println(fileRDD.toDebugString)
    println("----------------------")

    val wordRDD: RDD[String] = fileRDD.flatMap(_.split(" "))
    println(wordRDD.toDebugString)
    println("----------------------")

    val mapRDD: RDD[(String, Int)] = wordRDD.map((_,1))
    println(mapRDD.toDebugString)
    println("----------------------")

    val resultRDD: RDD[(String, Int)] = mapRDD.reduceByKey(_+_)
    println(resultRDD.toDebugString)

    resultRDD.collect()
  }
}

运算结果:

(2) input/word.txt MapPartitionsRDD[1] at textFile at Spark_RDD_Operator_Dependent_Study1.scala:17 []
 |  input/word.txt HadoopRDD[0] at textFile at Spark_RDD_Operator_Dependent_Study1.scala:17 []
----------------------
(2) MapPartitionsRDD[2] at flatMap at Spark_RDD_Operator_Dependent_Study1.scala:21 []
 |  input/word.txt MapPartitionsRDD[1] at textFile at Spark_RDD_Operator_Dependent_Study1.scala:17 []
 |  input/word.txt HadoopRDD[0] at textFile at Spark_RDD_Operator_Dependent_Study1.scala:17 []
----------------------
(2) MapPartitionsRDD[3] at map at Spark_RDD_Operator_Dependent_Study1.scala:25 []
 |  MapPartitionsRDD[2] at flatMap at Spark_RDD_Operator_Dependent_Study1.scala:21 []
 |  input/word.txt MapPartitionsRDD[1] at textFile at Spark_RDD_Operator_Dependent_Study1.scala:17 []
 |  input/word.txt HadoopRDD[0] at textFile at Spark_RDD_Operator_Dependent_Study1.scala:17 []
----------------------
(2) ShuffledRDD[4] at reduceByKey at Spark_RDD_Operator_Dependent_Study1.scala:29 []
 +-(2) MapPartitionsRDD[3] at map at Spark_RDD_Operator_Dependent_Study1.scala:25 []
    |  MapPartitionsRDD[2] at flatMap at Spark_RDD_Operator_Dependent_Study1.scala:21 []
    |  input/word.txt MapPartitionsRDD[1] at textFile at Spark_RDD_Operator_Dependent_Study1.scala:17 []
    |  input/word.txt HadoopRDD[0] at textFile at Spark_RDD_Operator_Dependent_Study1.scala:17 []

二、RDD 依赖关系

依赖关系,其实就是 RDD 之间的关系。

通过 rdd.dependencies 查看依赖关系:

package spark.core.dependent

import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.rdd.RDD

/**
 * RDD 依赖关系
 */
object Spark_RDD_Operator_Dependent_Study2 {
  def main(args: Array[String]): Unit = {
    val sparkConf = new SparkConf().
      setMaster("local[*]").
      set("spark.driver.host", "localhost").
      setAppName("rdd")
    val sc = new SparkContext(sparkConf)

    val fileRDD: RDD[String] = sc.textFile("input/word.txt")
    println(fileRDD.dependencies)
    println("----------------------")

    val wordRDD: RDD[String] = fileRDD.flatMap(_.split(" "))
    println(wordRDD.dependencies)
    println("----------------------")

    val mapRDD: RDD[(String, Int)] = wordRDD.map((_,1))
    println(mapRDD.dependencies)
    println("----------------------")

    val resultRDD: RDD[(String, Int)] = mapRDD.reduceByKey(_+_)
    println(resultRDD.dependencies)

    resultRDD.collect()
  }
}

运算结果:

List(org.apache.spark.OneToOneDependency@dab48d3)
----------------------
List(org.apache.spark.OneToOneDependency@1639f93a)
----------------------
List(org.apache.spark.OneToOneDependency@2eaef76d)
----------------------
List(org.apache.spark.ShuffleDependency@2436ea2f)

三、RDD 窄依赖

窄依赖表示每一个父 RDD 的 Partition 最多被子 RDD 的一个 Partition 使用。

class OneToOneDependency[T](rdd: RDD[T]) extends NarrowDependency[T](rdd) 

四、RDD 宽依赖

宽依赖表示同一个父 RDD 的 Partition 被多个子 RDD 的 Partition 依赖,会引起 Shuffle。

class ShuffleDependency[K: ClassTag, V: ClassTag, C: ClassTag](
    @transient private val _rdd: RDD[_ <: Product2[K, V]],
    val partitioner: Partitioner,
    val serializer: Serializer = SparkEnv.get.serializer,
    val keyOrdering: Option[Ordering[K]] = None,
    val aggregator: Option[Aggregator[K, V, C]] = None,
    val mapSideCombine: Boolean = false)
  extends Dependency[Product2[K, V]] 

五、RDD 阶段划分

DAG(Directed Acyclic Graph)有向无环图是由点和线组成的拓扑图形,该图形具有方向,不会闭环。例如,DAG 记录了RDD 的转换过程和任务的阶段。
在这里插入图片描述

spark 划分阶段中遇到一个 shuffle 操作就会阶段数加 1。

六、RDD 任务划分

RDD 任务切分中间分为:Application、Job、Stage 和 Task
Application:初始化一个 SparkContext 即生成一个Application
Job:一个 Action 算子就会生成一个 Job
Stage:Stage 等于宽依赖(ShuffleDependency)的个数加 1
Task:一个 Stage 阶段中,最后一个 RDD 的分区个数就是 Task 的个数
注意:Application -> Job -> Stage -> Task每一层都是 1 对 n 的关系。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值