一篇文章搞清spark任務如何執行

南宮飽虎發表於2020-03-20

本文將針對spark中的Driver和Executor講起,簡述了spark的執行流程,部署模式以及內部任務排程機制,希望針對spark任務執行過程進行儘可能好理解的解析

1.兩個重要的主角

​ 在spark中,有兩個重要的主角是繞不開的,driver和executor,他們的結構呈一主多從模式,driver就是那個單身狗,控制慾很強,權利也很大,每天獨自一人沒別的事,就想法設法的指揮著手下一堆executor到處幹活。他們分工明確,組織結構簡單,共同支撐起了spark強大的計算引擎。

Driver

​ Spark 驅動器節點,用於執行 Spark 任務中的 main 方法,負責實際程式碼的執行工作。Driver 在 Spark 作業執行時主要負責:

  1. 將程式碼邏輯轉化為任務;

  2. 在 Executor 之間排程任務(job);

  3. 跟蹤 Executor 的執行情況(task)。

Executor

​ Spark 執行器節點,負責在 Spark 作業中執行具體任務,任務之間相互獨立。Spark 應用啟動時,Executor 節點被同時啟動,並且始終伴隨著整個 Spark 應用的生命週期而存在。如果有 Executor 點發生了故障或崩潰,Spark 應用也可以繼續執行,會將出錯節點上的任務排程到其他 Executor 節點上繼續執行。Executor 有兩個核心功能:

  1. 負責執行組成 Spark 應用的任務,並將結果返回給驅動器程式;

  2. 通過自身的塊管理器(Block Manager)為使用者程式中要求快取的 RDD提供記憶體式儲存。RDD 是直接快取在 Executor 程式內的,因此任務可以在執行時充分利用快取資料加速運算。

Spark 執行流程

一篇文章搞清spark任務如何執行

​ 不論spark以何種方式部署,在任務提交後,都先啟動Driver,然後Driver向叢集管理器註冊應用程式,之後叢集管理器根據此任務的配置檔案分配Executor並啟動,然後Driver等待資源滿足,執行 main 函式,Spark的查詢為懶執行,當執行到 action 運算元時才開始真正執行,開始反向推算,根據寬依賴進行 stage 的劃分,隨後每一個 stage 對應一個 taskset,一個taskset 中有多個 task,task 會被分發到指定的 Executor 去執行,在任務執行的過程中,Executor 也會不斷與 Driver 進行通訊,報告任務執行情況。

2.spark的部署模式

2.1 spark部署型別

Spark共支援3種叢集管理器,Standalone,Mesos和Yarn

  • Standalone:

獨立模式,Spark 原生的最簡單的一個叢集管理器。 它可以執行在各種作業系統上,自帶完整的服務,無需依賴任何其他資源管理系統,使用 Standalone 可以很方便地搭建一個叢集。

  • Apache Mesos

    Mesos也是一個強大的分散式資源管理框架,是以與Linux核心同樣的原則而建立的,允許多種不同的框架部署在其上

  • Hadoop Yarn

    Hadoop生態下的統一資源管理機制,在上面可以執行多套計算框架,如mapreduce、spark 等,根據 driver 在叢集中的位置不同,部署模式可以分為 yarn-client 和 yarn-cluster。

    Spark 的執行模式取決於傳遞給 SparkContext 的 MASTER 環境變數的值,spark在yarn上部署:

    1. yarn-client:Driver在本地,Executor在Yarn叢集,配置:--deploy-mode client
    2. yarn-cluster:Driver和Executor都在Yarn叢集,配置:--deploy-mode cluster

2.2 Yarn模式下的執行機制

當前流行的工作模式均是將spark提交到Yarn上,所以這裡我們針對spark on Yarn做一下詳細瞭解。

  • yarn-client 模式

​ 在YARNClient模式下,Driver在任務提交的本地機器上執行,Driver會向ResourceManager申請啟動ApplicationMaster,隨後ResourceManager分配container,在合適的NodeManager上啟動ApplicationMaster,此時的ApplicationMaster的功能相當於一個ExecutorLaucher,只負責向ResourceManager申請Executor記憶體。   ResourceManager接到ApplicationMaster的資源申請後會分配container,然後 ApplicationMaster在資源分配指定的NodeManager上啟動Executor程式,Executor程式啟動後會向Driver反向註冊。另外一條線,Driver自身資源滿足的情況下,Driver開始執行main函式,之後執行Action運算元時,觸發一個job,並根據寬依賴開始劃分stage,每個stage生成對應的taskSet,Executor註冊完成後,Driver將task分發到各個Executor上執行。

一篇文章搞清spark任務如何執行

  • yarn-cluster

​ 在 YARN Cluster 模式下,任務提交後會和 ResourceManager 通訊申請啟動ApplicationMaster,隨後 ResourceManager 分配 container,在合適的 NodeManager上啟動 ApplicationMaster,此時的ApplicationMaster 就是 Driver。

​ Driver 啟動後向 ResourceManager 申請 Executor 記憶體,ResourceManager會分配container,然後在合適的 NodeManager 上啟動 Executor 程式,Executor 程式啟動後會向 Driver 反向註冊。另外一條線,Driver自身資源滿足的情況下,開始執行main函式,之後執行Action運算元時,觸發一個job,並根據寬依賴開始劃分stage,每個stage生成對應的taskSet,Executor註冊完成後,Driver將task分發到各個Executor上執行。

一篇文章搞清spark任務如何執行

3.Spark 任務排程

​ Driver會根據使用者程式準備任務,並向Executor分發任務,在這兒有幾個Spark的概念需要先介紹一下:

  • Job:以Action運算元為界,遇到一個Action方法就觸發一個Job

  • Stage:Job的子集,一個job至少有一個stage,以shuffle(即RDD寬依賴)為界,一個shuffle劃分一個stage

  • Task: Stage 的子集,以並行度(分割槽數)來衡量,分割槽數是多少,則有多少

    個 task。

spark在具體任務的排程中,總的分兩路進行:Stage級別排程和Task級別排程。Spark RDD通過轉換(Transactions)運算元,形成了血緣關係圖DAG,最後通過行動(Action)運算元,觸發Job並排程執行。

DAGScheduler負責Stage級的排程,主要是將DAG切分成若干Stages,並將每個Stage打包成TaskSet交給TaskScheduler排程。

TaskScheduler負責Task級的排程,將DAGScheduler給過來的TaskSet按照指定的排程策略分發到Executor上執行

3.1 Spark Stage級排程

​ Spark的任務排程是從DAG切割開始,主要是由DAGScheduler來完成。當遇到一個Action操作後就會觸發一個Job的計算,並交給DAGScheduler來處理。

DAGScheduler主要做兩個部分的事情:

  1. 切分stage

​ DAGScheduler會根據RDD的血緣關係構成的DAG進行切分,將一個Job劃分為若干Stages,具體劃分策略是:從後往前,由最終的RDD不斷通過依賴回溯判斷父依賴是否是寬依賴,遇到一個shuffle就劃分一個Stage。無shuffle的稱為窄依賴,窄依賴之間的RDD被劃分到同一個Stage中。劃分的Stages分兩類,一類叫做ResultStage,為DAG最下游的Stage,由Action方法決定,另一類叫做ShuffleMapStage,為下游Stage準備資料。

​ stage任務排程本身是一個反向的深度遍歷演算法,以下圖wordcount為例。此處只有saveAsTextFile為行動運算元,該 Job 由 RDD-3 和 saveAsTextFile方法組成,根據依賴關係回溯,知道回溯至沒有依賴的RDD-0。回溯過程中,RDD-2和RDD-3存在reduceByKey的shuffle,會劃分stage,由於RDD-3在最後一個stage,即劃為ResultStage,RDD-2,RDD-1,RDD-0,這些依賴之間的轉換運算元flatMap,map沒有shuffle,因為他們之間是窄依賴,劃分為ShuffleMapStage。

一篇文章搞清spark任務如何執行

  1. 打包Taskset提交Stage

​ 一個Stage如果沒有父Stage,那麼從該Stage開始提交,父Stage執行完畢才能提交子Stage。Stage提交時會將Task資訊(分割槽資訊以及方法等)序列化並被打包成TaskSet交給TaskScheduler,一個Partition對應一個Task,另一方面TaskScheduler會監控Stage的執行狀態,只有Executor丟失或者Task由於Fetch失敗才需要重新提交失敗的Stage以排程執行失敗的任務,其他型別的Task失敗會在TaskScheduler的排程過程中重試。

3.2 Spark Task 級排程

​ SparkTask的排程是由TaskScheduler來完成,TaskScheduler將接收的TaskSet封裝為TaskSetManager加入到排程佇列中。同一時間可能存在多個TaskSetManager,一個TaskSetManager對應一個TaskSet,而一個TaskSet含有n多個task資訊,這些task都是同一個stage的。

​ TaskScheduler初始化後會啟動SchedulerBackend,它負責跟外界打交道,接收Executor的註冊資訊,並維護Executor的狀態,SchedulerBackend會監控到有資源後,會詢問TaskScheduler有沒有任務要執行,TaskScheduler會從排程佇列中按照指定的排程策略選擇TaskSetManager去排程執行。

​ TaskSetManager按照一定的排程規則一個個取出task給TaskScheduler,TaskScheduler再交給SchedulerBackend去發到Executor上執行。

​ Task被提交到Executor啟動執行後,Executor會將執行狀態上報給SchedulerBackend,SchedulerBackend則告訴TaskScheduler,TaskScheduler找到該Task對應的TaskSetManager,並通知到該TaskSetManager,這樣TaskSetManager就知道Task的執行狀態

3.3 失敗重試和白名單

​ 對於執行失敗的Task,TaskSetManager會記錄它失敗的次數,如果失敗次數還沒有超過最大重試次數,那麼就把它放回待排程的Task池子中等待重新執行,當重試次數過允許的最大次數,整個Application失敗。在記錄Task失敗次數過程中,TaskSetManager還會記錄它上一次失敗所在的ExecutorId和Host,這樣下次再排程這個Task時,會使用黑名單機制,避免它被排程到上一次失敗的節點上,起到一定的容錯作用。

相關文章