什么是DAG
在Spark里每一個操作生成一個RDD,RDD之間連一條邊,最后這些RDD和他們之間的邊組成一個有向無環(huán)圖,這個就是DAG。
Spark 為什么要構(gòu)建DAG?
Spark會根據(jù)寬依賴窄依賴來劃分具體的Stage,而依賴有2個作用:
- 用來解決數(shù)據(jù)容錯的高效性;
- 其二用來劃分stage。
RDD的依賴關(guān)系分為兩種:窄依賴(Narrow Dependencies)與寬依賴(Wide Dependencies,源碼中稱為Shuffle Dependencies)

-
窄依賴
每個父RDD的一個Partition最多被子RDD的一個Partition所使用(1:1 或 n:1)。例如map、filter、union等操作都會產(chǎn)生窄依賴;
子RDD分區(qū)通常對應(yīng)常數(shù)個父RDD分區(qū)(O(1),與數(shù)據(jù)規(guī)模無關(guān))。 -
寬依賴
一個父RDD的Partition會被多個子RDD的Partition所使用,例如groupByKey、reduceByKey、sortByKey等操作都會產(chǎn)生寬依賴;(1:m 或 n:m)
子RDD分區(qū)通常對應(yīng)所有的父RDD分區(qū)(O(n),與數(shù)據(jù)規(guī)模有關(guān))
DAG的生成

原始的RDD通過一系列的轉(zhuǎn)換就形成了DAG,有了計算的DAG圖,Spark內(nèi)核下一步的任務(wù)就是根據(jù)DAG圖將計算劃分成任務(wù)集,也就是Stage,這樣可以將任務(wù)提交到計算節(jié)點進行真正的計算。Spark計算的中間結(jié)果默認(rèn)是保存在內(nèi)存中的,Spark在劃分Stage的時候會充分考慮在分布式計算中可流水線計算(pipeline)的部分來提高計算的效率,而在這個過程中Spark根據(jù)RDD之間依賴關(guān)系的不同將DAG劃分成不同的Stage(調(diào)度階段)。對于窄依賴,partition的轉(zhuǎn)換處理在一個Stage中完成計算。對于寬依賴,由于有Shuffle的存在,只能在parent RDD處理完成后,才能開始接下來的計算,因此寬依賴是劃分Stage的依據(jù)。
Spark Works By DAG

Spark 執(zhí)行時有下面所列的流程:
用戶代碼定義RDD的有向無環(huán)圖
RDD上的操作會創(chuàng)建新的RDD,并引用它們的父節(jié)點,這樣就創(chuàng)建了一個圖。行動操作把有向無環(huán)圖強制轉(zhuǎn)譯為執(zhí)行計劃
當(dāng)調(diào)用RDD的一個行動操作時,這個RDD就必須被計算出來。這也要求計算出該RDD的父節(jié)點。Spark調(diào)度器提交一個作業(yè)來計算出所有必要的RDD。這個作業(yè)會包含一個或多個步驟,每個步驟其實也就是一波并行執(zhí)行的計算任務(wù)。一個步驟對應(yīng)有向五環(huán)圖中的一個或多個RDD,一個步驟對應(yīng)多個RDD是因為發(fā)生了流水線執(zhí)行。任務(wù)于集群中調(diào)度并執(zhí)行
步驟是按順序處理的,任務(wù)則獨立的啟動來計算出RDD的一部分。一旦作業(yè)的最后一個步驟結(jié)束,一個行動操作也就執(zhí)行完了。
注:在一個給定的Spark應(yīng)用中,由于需要創(chuàng)建一系列新的RDD,因此上述階段會連續(xù)發(fā)生很多次