小知識點源碼解析-STAGE由最後一個RDD確定並行度的源碼解析

以ShuffleMapStage 爲例進行解析。

1      假設

RDD A – ShuffleDependency – RDD B

即 RDD B依賴 RDD A,並且依賴關係爲寬依賴—— 依賴,針對的是兩個RDD之間的關係,RDD可以有多個父依賴RDD,但針對每個父依賴RDD都會有對應的具體依賴。

2      關鍵源碼及其解析

關鍵源碼爲DAGScheduler類中構建ShuffleMapStage 的代碼—— 該方法中同時包含了Stage複用的概念。

  /**

   * Create a shuffle map Stage for the given RDD.  The stage will also be associated with the

   * provided firstJobId.  If a stage for the shuffleId existed previously so that the shuffleId is

   * present in the MapOutputTracker, then the number and location of available outputs are

   * recovered from the MapOutputTracker

   */

  private def newOrUsedShuffleStage(

      shuffleDep: ShuffleDependency[_, _, _],

      firstJobId: Int): ShuffleMapStage = {

 

// 根據假設: RDD B 依賴 RDD A,此時,shuffleDep表示兩者直接的依賴關係,

// 對應的shuffleDep.rdd 爲 RDD A, 即RDD A 是當前Stage的最後一個RDD

val rdd = shuffleDep.rdd

// 傳入的任務數numTasks,對應的是Stage 最後一個RDD(即RDD A)

// 的分區個數。

// 而在後續由 ShuffleMapStage構建 ShuffleMapTask 時numTasks會

// 控制Task的個數,因此該Stage 的並行度是由其最後一個RDD的分區控制。

// 對應也體現了,是被寬依賴的 RDD A 需要根據 RDD B 所需的數據結構進行重組

// 重組的數據存入磁盤中(當前實現)

val numTasks = rdd.partitions.length

    val stage = newShuffleMapStage(rdd, numTasks, shuffleDep, firstJobId, rdd.creationSite)

    if (mapOutputTracker.containsShuffle(shuffleDep.shuffleId)) {

      val serLocs = mapOutputTracker.getSerializedMapOutputStatuses(shuffleDep.shuffleId)

      val locs = MapOutputTracker.deserializeMapStatuses(serLocs)

      (0 until locs.length).foreach { i =>

        if (locs(i) ne null) {

          // locs(i) will be null if missing

          stage.addOutputLoc(i, locs(i))

        }

      }

    } else {

      // Kind of ugly: need to register RDDs with the cache and map output tracker here

      // since we can't do it in the RDD constructor because # of partitions is unknown

      logInfo("Registering RDD " + rdd.id + " (" + rdd.getCreationSite + ")")

      mapOutputTracker.registerShuffle(shuffleDep.shuffleId, rdd.partitions.length)

    }

    stage

  }

 

ShuffleMapTask構建的對應代碼在DAGScheduler類的submitMissingTasks方法中,具體如下:

    val tasks: Seq[Task[_]] = try {

      stage match {

        case stage: ShuffleMapStage =>

          partitionsToCompute.map { id =>

            val locs = taskIdToLocations(id)

            val part = stage.rdd.partitions(id)

            new ShuffleMapTask(stage.id, stage.latestInfo.attemptId,

              taskBinary, part, locs, stage.internalAccumulators)

          }

 

3      擴展

Stage 是由最後一個RDD的分區數控制並行度,因此在進行重分區時,需要注意最後的分區個數如果過小,則並行度降低,進而影響效率。此時可以採用寬依賴,切分Stage,保證前面的並行度不會降低。

比如,使用coalesce將大分區數合併成小分區數時,由於沒有Shuffle(默認),此時最終執行的並行度爲合併後的小分區個數 —— 可以考慮默認Shuffle爲true的 repartition方法,認爲加上寬依賴,保證前面計算的高並行度。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章