Spark任務如何執行?

Spark執行模型

       Spark執行模型可以分爲三部分:創建邏輯計劃,將其翻譯爲物理計劃,在集羣上執行task。
       可以在http://<driver-node>:4040上查看關於Spark Jobs的信息。對於已經完成的Spark應用,可以在http://<server-url>:18080上查看信息。
       下面來瀏覽一下這三個階段。

邏輯執行計劃

       第一階段,邏輯執行計劃被創建。這個計劃展示了哪些steps被執行。回顧一下,當對一個Dataset執行一個轉換操作,會有一個新的Dataset被創建。這時,新的Dataset會指向其父Dataset,最終形成一個有向無環圖(DAG)。

物理執行計劃

       行動操作會觸發邏輯DAG圖向物理執行計劃的轉換。Spark Catalyst query optimizer會爲DataFrames創建物理執行計劃,如下圖所示:



       物理執行計劃標識執行計劃的資源,例如內存分區和計算任務。

查看邏輯執行計劃和物理執行計劃

       可以調用explain(true)方法查看邏輯和物理執行計劃。如下例所示:

import org.apache.spark.sql.types._
import org.apache.spark.sql._
import org.apache.spark.sql.functions._
var file = “maprfs:///data/flights20170102.json”
case class Flight(_id: String, dofW: Long, carrier: String,
origin: String, dest: String, crsdephour: Long, crsdeptime:
Double, depdelay: Double,crsarrtime: Double, arrdelay: Double,
crselapsedtime: Double, dist: Double) extends Serializable
val df = spark.read.format(“json”).option(“inferSchema”, “true”).
load(file).as[Flight]
val df2 = df.filter($”depdelay” > 40)
df2.take(1)
result:
Array[Flight] = Array(Flight(MIA_IAH_2017-01-01_AA_2315,
7,AA,MIA,IAH,20,2045.0,80.0,2238.0,63.0,173.0,964.0))
df2.explain(true)
result:
== Parsed Logical Plan ==
‘Filter (‘depdelay > 40)
+- Relation[_id#8,arrdelay#9,…] json
== Analyzed Logical Plan ==
_id: string, arrdelay: double…
Filter (depdelay#15 > cast(40 as double))
+- Relation[_id#8,arrdelay#9…] json
== Optimized Logical Plan ==
Filter (isnotnull(depdelay#15) && (depdelay#15 > 40.0))
+- Relation[_id#8,arrdelay#9,…] json
== Physical Plan ==
*Project [_id#8, arrdelay#9,…]
+- *Filter (isnotnull(depdelay#15) && (depdelay#15 > 40.0))
+- *FileScan json [_id#8,arrdelay#9,…] Batched: false, Format:
JSON, Location: InMemoryFileIndex[maprfs:///..],

       在web頁面http://<driver-node>:4040/SQL/上可以看到計劃生成的更多細節。


       在以下的代碼中,我們看到df3的物理計劃由FileScan、Filter、Project、HashAggregate、Exchange以及HashAggregate組成。Exchange是由groupBy轉換導致的shuffle。Spark在每次shuffle之前對Exchange的數據進行hash aggregation。在shuffle後會針對之前的子aggragation進行一次hash aggregation。

val df3 = df2.groupBy(“carrier”).count
df3.collect
result:
Array[Row] = Array([UA,2420], [AA,757], [DL,1043], [WN,244])
df3.explain
result:
== Physical Plan ==
*HashAggregate(keys=[carrier#124], functions=[count(1)])
+- Exchange hashpartitioning(carrier#124, 200)
+- *HashAggregate(keys=[carrier#124], functions=[partial_
count(1)])
+- *Project [carrier#124]
+- *Filter (isnotnull(depdelay#129) && (depdelay#129 >
40.0))
+- *FileScan json [carrier#124,depdelay#129]

在集羣上執行tasks

       第三階段,tasks在集羣上被調度執行。scheduler將根據轉換操作將DAG圖劃分爲stage。窄依賴轉換操作(沒有數據移動的轉換)將被分組到一個單一的stage中。



       每個stage由基於partitions的task組成,這些任務將並行執行相同計算。



       scheduler將這些stage task提交給task scheduler,task scheduler通過cluster manager啓動task。

       以下是關於執行組成的一些總結:

  • Task:單臺機器上運行的執行單元。
  • Stage:基於partitions的一組task,執行並行計算。
  • Job:具有一個或多個stages。
  • Pipelining:當數據集轉換操作時沒有數據移動時,將Datasets摺疊爲單一stage。
  • DAG:數據集操作時的邏輯視圖。

       Tasks的數量取決於partitions:在第一個階段讀取文件時,有2個partitions;shuffle過後,partitions的數量爲200.可以通過rdd.partitions.size方法查看Dataset的partition數量。

df3.rdd.partitions.size
result: Int = 200
df2.rdd.partitions.size
result: Int = 2
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章