一. 概念
一個Application由一個Driver和若干個Job構成,
一個Job由多個Stage構成,
一個Stage由多個沒有Shuffle關係的Task組成(多個RDD算子操作)
stage:寬窄依賴劃分
當執行一個Application時,Driver會向集羣管理器申請資源,啓動Executor,並向Executor發送應用程序代碼和文件,然後在Executor上執行Task,運行結束後,執行結果會返回給Driver,或者寫到HDFS或者其他數據庫中.
二. 作業調度流程
- 構建Spark Application的運行環境(啓動SparkContext),SparkContext向資源管理器(可以是Standalone、Mesos或YARN)註冊並申請運行Executor資源;
- 資源管理器分配Executor資源並啓動StandaloneExecutorBackend,Executor運行情況將隨着心跳發送到資源管理器上;
- SparkContext構建成DAG圖,將DAG圖分解成Stage,並把Taskset發送給Task Scheduler。Executor向SparkContext申請Task
- Task Scheduler將Task發放給Executor運行同時SparkContext將應用程序代碼發放給Executor。
- Task在Executor上運行,運行完畢釋放所有資源。
三. Spark運行架構具有以下特點
(1)每個Application獲取專屬的executor進程,該進程在Application期間一直駐留,並以多線程方式運行tasks。這種Application隔離機制有其優勢的,無論是從調度角度看(每個Driver調度它自己的任務),還是從運行角度看(來自不同Application的Task運行在不同的JVM中)。當然,這也意味着Spark Application不能跨應用程序共享數據,除非將數據寫入到外部存儲系統。
(2)Spark與資源管理器無關,只要能夠獲取executor進程,並能保持相互通信就可以了。
(3)提交SparkContext的Client應該靠近Worker節點(運行Executor的節點),最好是在同一個Rack裏,因爲Spark Application運行過程中SparkContext和Executor之間有大量的信息交換;如果想在遠程集羣中運行,最好使用RPC將SparkContext提交給集羣,不要遠離Worker運行SparkContext。
(4)Task採用了數據本地性和推測執行的優化機制。
四. spark 詳細運行過程
1)
- Driver程序的代碼運行到action操作,觸發了SparkContext的runJob方法。
- SparkContext調用DAGScheduler的runJob函數。
- DAGScheduler把Job劃分stage,然後把stage轉化爲相應的Tasks,把Tasks交給TaskScheduler。
- 通過TaskScheduler把Tasks添加到任務隊列當中,交給SchedulerBackend進行資源分配和任務調度, 每個tasks就有多個Threads, 在worker中process(運行)。
- 調度器給Task分配執行Executor,ExecutorBackend負責執行Task。Executor執行結束後,回傳給Driver,把執行結果存儲到本地或hdfs上
2)
- Driver程序的代碼運行到action操作,觸發了SparkContext的runJob方法。
- SparkContext調用DAGScheduler的runJob函數。
- DAGScheduler把Job劃分stage,然後 DAGScheduler把Job提交stage,DAGScheduler把stage轉化爲相應的TaskSet,把TaskSet交給TaskScheduler。
- 通過TaskScheduler把Tasks添加到任務隊列當中,並把計算任務提交給調度器SchedulableBuilder
- 調度器SchedulableBuilder調度任務TaskScheduler
- TaskScheduler爲task分配任務資源,並提交tasks給SchedulerBackend
- 交給SchedulerBackend進行資源分配和任務調度, 將任務提交到Executor上運行, 在Executor(worker)中process(運行)。
- 調度器給Task分配執行Executor,ExecutorBackend負責執行Task。Executor執行結束後,回傳給Driver,把執行結果存儲到本地或hdfs上
3)
- 我們提交一個任務,任務就叫Application
初始化程序的入口SparkContext,
1.1 初始化DAG Scheduler
1.2 初始化Task Scheduler - Task Scheduler中的ClientEndpoint向master去進行註冊並申請資源(CPU Core和Memory)
- Master根據SparkContext的資源申請要求和Worker心跳週期內報告的信息決定在哪個Worker上分配資源,然後在該Worker上獲取資源,然後啓動StandaloneExecutorBackend;順便初始化好了一個線程池,通知worker啓動Executor
- StandaloneExecutorBackend向Driver(SparkContext)註冊,這樣Driver就知道哪些Executor爲他進行服務了。
到這個時候其實我們的初始化過程基本完成了,我們開始執行transformation的代碼,但是代碼並不會真正的運行,直到我們遇到一個action操作。生產一個job任務,進行stage的劃分 - 發送任務到Executor進行執行
5.1 SparkContext將Applicaiton代碼發送給Standalone ExecutorBackend;並且SparkContext解析Applicaiton代碼,構建DAG圖,並提交給DAG Scheduler分解成Stage(當碰到Action操作時,就會催生Job;每個Job中含有1個或多個Stage,Stage一般在獲取外部數據和shuffle之前產生)。
5.2 將Stage(或者稱爲TaskSet)提交給Task Scheduler。Task Scheduler負責將Task分配到相應的Worker,最後提交給StandaloneExecutorBackend執行;
5.3 對task進行序列化,並根據task的分配算法,分配task
5.4 對接收過來的task進行反序列化,把task封裝成一個線程 - 開始執行Task,並向SparkContext報告,反饋任務狀態給Driver
- APPlication程序運行完畢後,回收資源