簡體   English   中英

spark DAG 中的 shufflequerystage 是什么?

[英]What is shufflequerystage in spark DAG?

我在 spark DAG 中看到的shufflequerystage box 是什么。 它與火花階段的excahnge盒有何不同?

在此處輸入圖像描述

這里已經有一個很好的答案,但這只是為了通過查看源代碼為您提供更多關於這個shufflequerystage實際上是什么的信息。

什么是隨機查詢階段?

如果我們查看ShuffleQueryStageExec案例類的 Spark 源代碼,我們會看到以下內容:

case class ShuffleQueryStageExec(
    override val id: Int,
    override val plan: SparkPlan,
    override val _canonicalized: SparkPlan) extends QueryStageExec {
...
}

所以ShuffleQueryStageExec extends QueryStageExec 那么讓我們看看QueryStageExec 代碼注釋很有啟發性:

查詢階段是查詢計划的獨立子圖。 查詢階段在繼續執行查詢計划的進一步運算符之前具體化其輸出。 物化輸出的數據統計可用於優化后續查詢階段。

有兩種查詢階段:

  1. 隨機查詢階段。 這個階段將其輸出具體化為隨機文件,Spark 啟動另一個作業來執行更多操作符。
  2. 廣播查詢階段。 此階段將其輸出具體化為驅動程序 JVM 中的一個數組。 Spark 在執行進一步的運算符之前廣播數組。

所以(非常)簡而言之, ShuffleQueryStage是您整個查詢計划的一部分,其數據統計信息可用於優化后續查詢階段。 這些都是自適應查詢執行(AQE) 的一部分。

這樣的Shuffle Query Stage是怎么做出來的呢?

為了更好地了解這一切是如何工作的,我們可以嘗試了解隨機查詢階段是如何進行的。 AdaptiveSparkPlanExec案例類是這方面的有趣位置。

有許多動作(收集、獲取、拖尾、執行……)會觸發withFinalPlanUpdate函數,而后者又會觸發getFinalPhysicalPlan函數。 在此函數中,將調用createQueryStages函數,這就是它變得有趣的地方。

createQueryStages函數是一個遍歷整個計划樹的遞歸函數,它看起來有點像這樣:

  private def createQueryStages(plan: SparkPlan): CreateStageResult = plan match {
    case e: Exchange =>
      // First have a quick check in the `stageCache` without having to traverse down the node.
      context.stageCache.get(e.canonicalized) match {
        case Some(existingStage) if conf.exchangeReuseEnabled =>
          ...

        case _ =>
          val result = createQueryStages(e.child)
          val newPlan = e.withNewChildren(Seq(result.newPlan)).asInstanceOf[Exchange]
          // Create a query stage only when all the child query stages are ready.
          if (result.allChildStagesMaterialized) {
            var newStage = newQueryStage(newPlan)
            ...
      }

所以你看,如果我們反彈到一個已經執行過的Exchange並且我們想重用它,我們就這樣做。 但如果不是這種情況,我們將創建一個新計划並調用newQueryStage函數。

故事到此結束。 newQueryStage 函數如下所示:

  private def newQueryStage(e: Exchange): QueryStageExec = {
    val optimizedPlan = optimizeQueryStage(e.child, isFinalStage = false)
    val queryStage = e match {
      case s: ShuffleExchangeLike =>
        ...
        ShuffleQueryStageExec(currentStageId, newShuffle, s.canonicalized)
      case b: BroadcastExchangeLike =>
        ...
        BroadcastQueryStageExec(currentStageId, newBroadcast, b.canonicalized)
    }
    ...
  }

所以我們看到正在制作ShuffleQueryStageExec 因此,對於每個Exchange ,這還沒有發生,或者如果您沒有重復使用交換,AQE 將添加ShuffleQueryStageExecBroadcastQueryStageExec

希望這能讓人們更深入地了解這是什么:)

shufflequerystage 連接到 AQE,它們在每個階段之后添加並進行交換,用於在每個階段之后具體化結果並根據統計信息優化剩余計划。

所以我的簡短回答是:

交換 - 在這里你的數據被洗牌

Shufflequerystage - 添加用於 AQE 目的以使用運行時統計信息和重新優化計划

在下面的示例中,我試圖展示這種機制

這是示例代碼:

import org.apache.spark.sql.functions._

spark.conf.set("spark.sql.autoBroadcastJoinThreshold", -1)
spark.conf.set("spark.sql.adaptive.enabled", true)

val input = spark.read
  .format("csv")
  .option("header", "true")
  .load(
    "dbfs:/FileStore/shared_uploads/**@gmail.com/city_temperature.csv"
  )
val dataForInput2 = Seq(
  ("Algeria", "3"),
  ("Germany", "3"),
  ("France", "5"),
  ("Poland", "7"),
  ("test55", "86")
)
val input2 = dataForInput2
  .toDF("Country", "Value")
  .withColumn("test", lit("test"))
val joinedDfs = input.join(input2, Seq("Country"))
val finalResult =
  joinedDfs.filter(input("Country") === "Poland").repartition(200)
finalResult.show 

我正在從文件中讀取數據,但你可以用代碼中創建的小 df 替換它,因為我添加了一行來禁用廣播。 我添加了一些 withColumn 和 repartition 以使其更有趣

首先讓我們看一下禁用 AQE 的計划:

== Physical Plan ==
CollectLimit (11)
+- Exchange (10)
   +- * Project (9)
      +- * SortMergeJoin Inner (8)
         :- Sort (4)
         :  +- Exchange (3)
         :     +- * Filter (2)
         :        +- Scan csv  (1)
         +- Sort (7)
            +- Exchange (6)
               +- LocalTableScan (5)

現在啟用 AQE

== Physical Plan ==
AdaptiveSparkPlan (25)
+- == Final Plan ==
   CollectLimit (16)
   +- ShuffleQueryStage (15), Statistics(sizeInBytes=1447.8 KiB, rowCount=9.27E+3, isRuntime=true)
      +- Exchange (14)
         +- * Project (13)
            +- * SortMergeJoin Inner (12)
               :- Sort (6)
               :  +- AQEShuffleRead (5)
               :     +- ShuffleQueryStage (4), Statistics(sizeInBytes=1158.3 KiB, rowCount=9.27E+3, isRuntime=true)
               :        +- Exchange (3)
               :           +- * Filter (2)
               :              +- Scan csv  (1)
               +- Sort (11)
                  +- AQEShuffleRead (10)
                     +- ShuffleQueryStage (9), Statistics(sizeInBytes=56.0 B, rowCount=1, isRuntime=true)
                        +- Exchange (8)
                           +- LocalTableScan (7)

代碼是一樣的,唯一不同的是 AQE 但現在你可以看到每次交換后都會彈出 ShuffleQueryStage

讓我們看一下示例中的 Dag 可視化。

首先讓我們看一下包含 join 的 job3

在此處輸入圖像描述

然后是 job4 ,它只是重用之前計算的內容,但使用 ShuffleQueryStage 添加了額外的第 4 階段,與您的情況類似

在此處輸入圖像描述

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM