【杂谈】RDD-依赖

RDD的依赖构成了它的血统(linage)--叫族谱更容易理解

有2种依赖关系:窄依赖和宽依赖

构成窄依赖关系的RDD,每一个分区对应一个task(一个线程),所有task可以并行运行;
宽依赖关系的RDD,要等到父RDD所有分区计算结束后,进行Shuffle,然后才能开始计算。

一个RDD可以依赖多个父RDD,在RDD中,依赖是一个集合

protected def getDependencies: Seq[Dependency[_]] = deps

针对每一个父RDD的依赖,是这样子定义的

// 依赖基类,抽象类
@DeveloperApi
abstract class Dependency[T] extends Serializable {
  def rdd: RDD[T]       // 父RDD
}

窄依赖

// 它是一个抽象类
@DeveloperApi
abstract class NarrowDependency[T](_rdd: RDD[T]) extends Dependency[T] {

  // 获得和分区(id)相对应的父RDD分区(id),不可能多个,这里应该是为了扩展,不会存在多个父RDD分区对应一个子RDD分区的场景
  def getParents(partitionId: Int): Seq[Int]

  override def rdd: RDD[T] = _rdd
}

// 1:1的窄依赖, 子RDD分区和父RDD分区是一一对应的,e.g. map()
class OneToOneDependency[T](rdd: RDD[T]) extends NarrowDependency[T](rdd) {
  override def getParents(partitionId: Int): List[Int] = List(partitionId)
}

// 范围依赖,是一种1:1的依赖,它是把RDD分区叠加起来,e.g. union()
class RangeDependency[T](rdd: RDD[T], inStart: Int, outStart: Int, length: Int)
   extends NarrowDependency[T](rdd) {

  override def getParents(partitionId: Int): List[Int] = {
    // 这个计算基于这样的模型:2个父RDD的分区,叠加到一起,当然,不改变相对顺序
    // e.g. PRDD1[p11, p12, p13] union PRDD2[p21, p22, p23] -> UnionRDD[p11, p12, p13, p21, p22, p23]
    // 当前,UnionRDD, inStart 一直为0
    // outStart,父RDD在UnionRDD中的起始位置,对于我们的例子,PRDD1在UnionRDD对应的outStart = 0; PRDD2在UnionRDD对应的outStart = 2
    if (partitionId >= outStart && partitionId < outStart + length) {
      List(partitionId - outStart + inStart)
    } else {
      Nil
    }
  }

宽依赖

宽依赖中,RDD分区是没有什么对应关系的,就是对应全部的分区

@DeveloperApi
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]] {

  override def rdd: RDD[Product2[K, V]] = _rdd.asInstanceOf[RDD[Product2[K, V]]]


      // 注册shuffle manager,shuffle manager管理着shuffle的整个过程:和mapreduce shuffle相似;父RDD分区的数据按分区号在内存中排序,如果数据量很大,就会溢写到磁盘;多个溢写磁盘的文件会需要进行一个归并排序;所有RDD的分区完成上面“写”的过程以后,数据会被shuffle到Reducer中的Executor
  val shuffleHandle: ShuffleHandle = _rdd.context.env.shuffleManager.registerShuffle(
    shuffleId, _rdd.partitions.length, this)
}

转载于:https://www.cnblogs.com/ivanny/p/spark_rdd_dependency.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值