【大數據計算引擎-Spark】 Spark 內核解析-上

Spark內核泛指Spark的核心運行機制,包括Spark核心組件的運行機制、Spark任務調度機制、Spark內存管理機制、Spark核心功能的運行原理等,熟練掌握Spark內核原理,能夠幫助我們更好地完成Spark代碼設計,並能夠幫助我們準確鎖定項目運行過程中出現的問題的癥結所在。

Spark 內核概述

Spark 核心組件回顧

Driver

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

  1. 將用戶程序轉化爲作業(job);
  2. 在Executor之間調度任務(task);
  3. 跟蹤Executor的執行情況;
  4. 通過UI展示查詢運行情況;

Executor

Spark Executor節點是一個JVM進程,負責在 Spark 作業中運行具體任務,任務彼此之間相互獨立。Spark 應用啓動時,Executor節點被同時啓動,並且始終伴隨着整個 Spark 應用的生命週期而存在。如果有Executor節點發生了故障或崩潰,Spark 應用也可以繼續執行,會將出錯節點上的任務調度到其他Executor節點上繼續運行。

Executor有兩個核心功能:

  1. 負責運行組成Spark應用的任務,並將結果返回給驅動器進程;
  2. 它們通過自身的塊管理器(Block Manager)爲用戶程序中要求緩存的 RDD 提供內存式存儲。RDD 是直接緩存在Executor進程內的,因此任務可以在運行時充分利用緩存數據加速運算。

Spark 通用運行流程概述

Spark核心運行流程
圖爲Spark通用運行流程,不論Spark以何種模式進行部署,任務提交後,都會先啓動Driver進程,隨後Driver進程向集羣管理器註冊應用程序,之後集羣管理器根據此任務的配置文件分配Executor並啓動,當Driver所需的資源全部滿足後,Driver開始執行main函數,Spark查詢爲懶執行,當執行到action算子時開始反向推算,根據寬依賴進行stage的劃分,隨後每一個stage對應一個taskset,taskset中有多個task,根據本地化原則,task會被分發到指定的Executor去執行,在任務執行的過程中,Executor也會不斷與Driver進行通信,報告任務運行情況。

Spark 部署模式

Spark支持3種集羣管理器(Cluster Manager),分別爲:

  1. Standalone:獨立模式,Spark原生的簡單集羣管理器,自帶完整的服務,可單獨部署到一個集羣中,無需依賴任何其他資源管理系統,使用Standalone可以很方便地搭建一個集羣;
  2. Apache Mesos:一個強大的分佈式資源管理框架,它允許多種不同的框架部署在其上,包括yarn;
  3. Hadoop YARN:統一的資源管理機制,在上面可以運行多套計算框架,如map reduce、storm等,根據driver在集羣中的位置不同,分爲yarn client和yarn cluster。
    實際上,除了上述這些通用的集羣管理器外,Spark內部也提供了一些方便用戶測試和學習的簡單集羣部署模式。由於在實際工廠環境下使用的絕大多數的集羣管理器是Hadoop YARN,因此我們關注的重點是Hadoop YARN模式下的Spark集羣部署。
    Spark的運行模式取決於傳遞給SparkContext的MASTER環境變量的值,個別模式還需要輔助的程序接口來配合使用,目前支持的Master字符串及URL包括:
Master URL Meaning
local 在本地運行,只有一個工作進程,無並行計算能力。
local[K] 在本地運行,有K個工作進程,通常設置K爲機器的CPU核心數量。
local[*] 在本地運行,工作進程數量等於機器的CPU核心數量。
spark://HOST:PORT 以Standalone模式運行,這是Spark自身提供的集羣運行模式,默認端口號: 7077。詳細文檔見:Spark standalone cluster。
mesos://HOST:PORT 在Mesos集羣上運行,Driver進程和Worker進程運行在Mesos集羣上,部署模式必須使用固定值:–deploy-mode cluster。詳細文檔見:MesosClusterDispatcher.
yarn-client 在Yarn集羣上運行,Driver進程在本地,Executor進程在Yarn集羣上,部署模式必須使用固定值:–deploy-mode client。Yarn集羣地址必須在HADOOP_CONF_DIR or YARN_CONF_DIR變量裏定義。
yarn-cluster 在Yarn集羣上運行,Driver進程在Yarn集羣上,Work進程也在Yarn集羣上,部署模式必須使用固定值:–deploy-mode cluster。Yarn集羣地址必須在HADOOP_CONF_DIR or YARN_CONF_DIR變量裏定義。

用戶在提交任務給Spark處理時,以下兩個參數共同決定了Spark的運行方式。
· –master MASTER_URL :決定了Spark任務提交給哪種集羣處理。
· –deploy-mode DEPLOY_MODE:決定了Driver的運行方式,可選值爲Client或者Cluster。

Standalone 模式運行機制

Standalone集羣有四個重要組成部分,分別是:

  1. Driver:是一個進程,我們編寫的Spark應用程序就運行在Driver上,由Driver進程執行;
  2. Master(RM):是一個進程,主要負責資源的調度和分配,並進行集羣的監控等職責;
  3. Worker(NM):是一個進程,一個Worker運行在集羣中的一臺服務器上,主要負責兩個職責,一個是用自己的內存存儲RDD的某個或某些partition;另一個是啓動其他進程和線程(Executor),對RDD上的partition進行並行的處理和計算。
  4. Executor:是一個進程,一個Worker上可以運行多個Executor,Executor通過啓動多個線程(task)來執行對RDD的partition進行並行計算,也就是執行我們對RDD定義的例如map、flatMap、reduce等算子操作。

Standalone Client 模式

Standalone Client 模式

在Standalone Client模式下,Driver在任務提交的本地機器上運行,Driver啓動後向Master註冊應用程序,Master根據submit腳本的資源需求找到內部資源至少可以啓動一個Executor的所有Worker,然後在這些Worker之間分配Executor,Worker上的Executor啓動後會向Driver反向註冊,所有的Executor註冊完成後,Driver開始執行main函數,之後執行到Action算子時,開始劃分stage,每個stage生成對應的taskSet,之後將task分發到各個Executor上執行。

Standalone Cluster模式

Standalone Cluster模式
在Standalone Cluster模式下,任務提交後,Master會找到一個Worker啓動Driver進程, Driver啓動後向Master註冊應用程序,Master根據submit腳本的資源需求找到內部資源至少可以啓動一個Executor的所有Worker,然後在這些Worker之間分配Executor,Worker上的Executor啓動後會向Driver反向註冊,所有的Executor註冊完成後,Driver開始執行main函數,之後執行到Action算子時,開始劃分stage,每個stage生成對應的taskSet,之後將task分發到各個Executor上執行。
注意
Standalone的兩種模式下(client/Cluster),Master在接到Driver註冊Spark應用程序的請求後,會獲取其所管理的剩餘資源能夠啓動一個Executor的所有Worker,然後在這些Worker之間分發Executor,此時的分發只考慮Worker上的資源是否足夠使用,直到當前應用程序所需的所有Executor都分配完畢,Executor反向註冊完畢後,Driver開始執行main程序。

Yarn 模式運行機制

Yarn Client 模式

Yarn Client 模式
在YARN Client模式下,Driver在任務提交的本地機器上運行,Driver啓動後會和ResourceManager通訊申請啓動ApplicationMaster,隨後ResourceManager分配container,在合適的NodeManager上啓動ApplicationMaster,此時的ApplicationMaster的功能相當於一個ExecutorLaucher,只負責向ResourceManager申請Executor內存。

ResourceManager接到ApplicationMaster的資源申請後會分配container,然後ApplicationMaster在資源分配指定的NodeManager上啓動Executor進程,Executor進程啓動後會向Driver反向註冊,Executor全部註冊完成後Driver開始執行main函數,之後執行到Action算子時,觸發一個job,並根據寬依賴開始劃分stage,每個stage生成對應的taskSet,之後將task分發到各個Executor上執行。

Yarn Cluster 模式

Yarn Cluster 模式

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

Driver啓動後向ResourceManager申請Executor內存,ResourceManager接到ApplicationMaster的資源申請後會分配container,然後在合適的NodeManager上啓動Executor進程,Executor進程啓動後會向Driver反向註冊,Executor全部註冊完成後Driver開始執行main函數,之後執行到Action算子時,觸發一個job,並根據寬依賴開始劃分stage,每個stage生成對應的taskSet,之後將task分發到各個Executor上執行。

Spark 通訊架構

Spark 通信架構概述

Spark2.x版本使用Netty通訊框架作爲內部通訊組件。spark 基於netty新的rpc框架借鑑了Akka的中的設計,它是基於Actor模型,如下圖所示:
Actor
Spark通訊框架中各個組件(Client/Master/Worker)可以認爲是一個個獨立的實體,各個實體之間通過消息來進行通信。具體各個組件之間的關係圖如下:
Spark通訊架構
Endpoint(Client/Master/Worker)有1個InBox和N個OutBox(N>=1,N取決於當前Endpoint與多少其他的Endpoint進行通信,一個與其通訊的其他Endpoint對應一個OutBox),Endpoint接收到的消息被寫入InBox,發送出去的消息寫入OutBox並被髮送到其他Endpoint的InBox中。

Spark 通訊架構解析

Spark通信架構如下圖所示:
Spark通信架構-2

  1. RpcEndpoint:RPC端點,Spark針對每個節點(Client/Master/Worker)都稱之爲一個Rpc端點,且都實現RpcEndpoint接口,內部根據不同端點的需求,設計不同的消息和不同的業務處理,如果需要發送(詢問)則調用Dispatcher;
  2. RpcEnv:RPC上下文環境,每個RPC端點運行時依賴的上下文環境稱爲RpcEnv;
  3. Dispatcher:消息分發器,針對於RPC端點需要發送消息或者從遠程RPC接收到的消息,分發至對應的指令收件箱/發件箱。如果指令接收方是自己則存入收件箱,如果指令接收方不是自己,則放入發件箱;
  4. Inbox:指令消息收件箱,一個本地RpcEndpoint對應一個收件箱,Dispatcher在每次向Inbox存入消息時,都將對應EndpointData加入內部ReceiverQueue中,另外Dispatcher創建時會啓動一個單獨線程進行輪詢ReceiverQueue,進行收件箱消息消費;
  5. RpcEndpointRef:RpcEndpointRef是對遠程RpcEndpoint的一個引用。當我們需要向一個具體的RpcEndpoint發送消息時,一般我們需要獲取到該RpcEndpoint的引用,然後通過該應用發送消息。
  6. OutBox:指令消息發件箱,對於當前RpcEndpoint來說,一個目標RpcEndpoint對應一個發件箱,如果向多個目標RpcEndpoint發送信息,則有多個OutBox。當消息放入Outbox後,緊接着通過TransportClient將消息發送出去。消息放入發件箱以及發送過程是在同一個線程中進行;
  7. RpcAddress:表示遠程的RpcEndpointRef的地址,Host Port。
  8. TransportClient:Netty通信客戶端,一個OutBox對應一個TransportClient,TransportClient不斷輪詢OutBox,根據OutBox消息的receiver信息,請求對應的遠程TransportServer;
  9. TransportServer:Netty通信服務端,一個RpcEndpoint對應一個TransportServer,接受遠程消息後調用Dispatcher分發消息至對應收發件箱;
    根據上面的分析,Spark通信架構的高層視圖如下圖所示:
    Spark通信架構高層視圖

Spark 任務調度機制

在工廠環境下,Spark集羣的部署方式一般爲YARN-Cluster模式,之後的內核分析內容中我們默認集羣的部署方式爲YARN-Cluster模式。

Spark 任務提交流程

Yarn-Cluster 任務提交流程
下面的時序圖清晰地說明了一個Spark應用程序從提交到運行的完整流程:
Spark任務提交時序圖
提交一個Spark應用程序,首先通過Client向ResourceManager請求啓動一個Application,同時檢查是否有足夠的資源滿足Application的需求,如果資源條件滿足,則準備ApplicationMaster的啓動上下文,交給ResourceManager,並循環監控Application狀態。

當提交的資源隊列中有資源時,ResourceManager會在某個NodeManager上啓動ApplicationMaster進程,ApplicationMaster會單獨啓動Driver後臺線程,當Driver啓動後,ApplicationMaster會通過本地的RPC連接Driver,並開始向ResourceManager申請Container資源運行Executor進程(一個Executor對應與一個Container),當ResourceManager返回Container資源,ApplicationMaster則在對應的Container上啓動Executor。

Driver線程主要是初始化SparkContext對象,準備運行所需的上下文,然後一方面保持與ApplicationMaster的RPC連接,通過ApplicationMaster申請資源,另一方面根據用戶業務邏輯開始調度任務,將任務下發到已有的空閒Executor上。

當ResourceManager向ApplicationMaster返回Container資源時,ApplicationMaster就嘗試在對應的Container上啓動Executor進程,Executor進程起來後,會向Driver反向註冊,註冊成功後保持與Driver的心跳,同時等待Driver分發任務,當分發的任務執行完畢後,將任務狀態上報給Driver。

從上述時序圖可知,Client只負責提交Application並監控Application的狀態。對於Spark的任務調度主要是集中在兩個方面: 資源申請和任務分發,其主要是通過ApplicationMaster、Driver以及Executor之間來完成。

Spark 任務調度概述

當Driver起來後,Driver則會根據用戶程序邏輯準備任務,並根據Executor資源情況逐步分發任務。在詳細闡述任務調度前,首先說明下Spark裏的幾個概念。一個Spark應用程序包括Job、Stage以及Task三個概念:
 Job是以Action方法爲界,遇到一個Action方法則觸發一個Job;
 Stage是Job的子集,以RDD寬依賴(即Shuffle)爲界,遇到Shuffle做一次劃分;
 Task是Stage的子集,以並行度(分區數)來衡量,分區數是多少,則有多少個task。
Spark的任務調度總體來說分兩路進行,一路是Stage級的調度,一路是Task級的調度,總體調度流程如下圖所示:
Spark 任務調度概述

Spark RDD通過其Transactions操作,形成了RDD血緣關係圖,即DAG,最後通過Action的調用,觸發Job並調度執行。DAGScheduler負責Stage級的調度,主要是將job切分成若干Stages,並將每個Stage打包成TaskSet交給TaskScheduler調度。TaskScheduler負責Task級的調度,將DAGScheduler給過來的TaskSet按照指定的調度策略分發到Executor上執行,調度過程中SchedulerBackend負責提供可用資源,其中SchedulerBackend有多種實現,分別對接不同的資源管理系統。有了上述感性的認識後,下面這張圖描述了Spark-On-Yarn模式下在任務調度期間,ApplicationMaster、Driver以及Executor內部模塊的交互過程:
Job提交和Task拆分

Driver初始化SparkContext過程中,會分別初始化DAGScheduler、TaskScheduler、SchedulerBackend以及HeartbeatReceiver,並啓動SchedulerBackend以及HeartbeatReceiver。SchedulerBackend通過ApplicationMaster申請資源,並不斷從TaskScheduler中拿到合適的Task分發到Executor執行。HeartbeatReceiver負責接收Executor的心跳信息,監控Executor的存活狀況,並通知到TaskScheduler。

Spark Stage級調度

Spark的任務調度是從DAG切割開始,主要是由DAGScheduler來完成。當遇到一個Action操作後就會觸發一個Job的計算,並交給DAGScheduler來提交,下圖是涉及到Job提交的相關方法調用流程圖。
Job提交調用棧

Job由最終的RDD和Action方法封裝而成,SparkContext將Job交給DAGScheduler提交,它會根據RDD的血緣關係構成的DAG進行切分,將一個Job劃分爲若干Stages,具體劃分策略是,由最終的RDD不斷通過依賴回溯判斷父依賴是否是寬依賴,即以Shuffle爲界,劃分Stage,窄依賴的RDD之間被劃分到同一個Stage中,可以進行pipeline式的計算,如上圖紫色流程部分。劃分的Stages分兩類,一類叫做ResultStage,爲DAG最下游的Stage,由Action方法決定,另一類叫做ShuffleMapStage,爲下游Stage準備數據,下面看一個簡單的例子WordCount。
WordCount實例
Job由saveAsTextFile觸發,該Job由RDD-3和saveAsTextFile方法組成,根據RDD之間的依賴關係從RDD-3開始回溯搜索,直到沒有依賴的RDD-0,在回溯搜索過程中,RDD-3依賴RDD-2,並且是寬依賴,所以在RDD-2和RDD-3之間劃分Stage,RDD-3被劃到最後一個Stage,即ResultStage中,RDD-2依賴RDD-1,RDD-1依賴RDD-0,這些依賴都是窄依賴,所以將RDD-0、RDD-1和RDD-2劃分到同一個Stage,即ShuffleMapStage中,實際執行的時候,數據記錄會一氣呵成地執行RDD-0到RDD-2的轉化。不難看出,其本質上是一個深度優先搜索算法。

**一個Stage是否被提交,需要判斷它的父Stage是否執行,只有在父Stage執行完畢才能提交當前Stage,如果一個Stage沒有父Stage,那麼從該Stage開始提交。**Stage提交時會將Task信息(分區信息以及方法等)序列化並被打包成TaskSet交給TaskScheduler,一個Partition對應一個Task,另一方面TaskScheduler會監控Stage的運行狀態,只有Executor丟失或者Task由於Fetch失敗才需要重新提交失敗的Stage以調度運行失敗的任務,其他類型的Task失敗會在TaskScheduler的調度過程中重試。

相對來說DAGScheduler做的事情較爲簡單,僅僅是在Stage層面上劃分DAG,提交Stage並監控相關狀態信息。TaskScheduler則相對較爲複雜,下面詳細闡述其細節。

Spark Task 級調度

Spark Task的調度是由TaskScheduler來完成,由前文可知,DAGScheduler將Stage打包到TaskSet交給TaskScheduler,TaskScheduler會將TaskSet封裝爲TaskSetManager加入到調度隊列中,TaskSetManager結構如下圖所示。
TaskManager結構

TaskSetManager負責監控管理同一個Stage中的Tasks,TaskScheduler就是以TaskSetManager爲單元來調度任務。
taskmanager-2

前面也提到,TaskScheduler初始化後會啓動SchedulerBackend,它負責跟外界打交道,接收Executor的註冊信息,並維護Executor的狀態,所以說SchedulerBackend是管“糧食”的,同時它在啓動後會定期地去“詢問”TaskScheduler有沒有任務要運行,也就是說,它會定期地“問”TaskScheduler“我有這麼餘量,你要不要啊”,TaskScheduler在SchedulerBackend“問”它的時候,會從調度隊列中按照指定的調度策略選擇TaskSetManager去調度運行,大致方法調用流程如下圖所示:

task調度流程

將TaskSetManager加入rootPool調度池中之後,調用SchedulerBackend的riviveOffers方法給driverEndpoint發送ReviveOffer消息;driverEndpoint收到ReviveOffer消息後調用makeOffers方法,過濾出活躍狀態的Executor(這些Executor都是任務啓動時反向註冊到Driver的Executor),然後將Executor封裝成WorkerOffer對象;準備好計算資源(WorkerOffer)後,taskScheduler基於這些資源調用resourceOffer在Executor上分配task。

調度策略

前面講到,TaskScheduler會先把DAGScheduler給過來的TaskSet封裝成TaskSetManager扔到任務隊列裏,然後再從任務隊列裏按照一定的規則把它們取出來在SchedulerBackend給過來的Executor上運行。這個調度過程實際上還是比較粗粒度的,是面向TaskSetManager的。
TaskScheduler是以樹的方式來管理任務隊列,樹中的節點類型爲Schdulable,葉子節點爲TaskSetManager,非葉子節點爲Pool,下圖是它們之間的繼承關係。
任務隊列繼承關係

TaskScheduler支持兩種調度策略,一種是FIFO,也是默認的調度策略,另一種是FAIR。在TaskScheduler初始化過程中會實例化rootPool,表示樹的根節點,是Pool類型。

FIFO調度策略

如果是採用FIFO調度策略,則直接簡單地將TaskSetManager按照先來先到的方式入隊,出隊時直接拿出最先進隊的TaskSetManager,其樹結構如下圖所示,TaskSetManager保存在一個FIFO隊列中。
FIFO調度策略內存結構

FAIR 調度策略

FAIR調度策略的樹結構如下圖所示:
FAIR調度策略內存結構

FAIR模式中有一個rootPool和多個子Pool,各個子Pool中存儲着所有待分配的TaskSetMagager。
在FAIR模式中,需要先對子Pool進行排序,再對子Pool裏面的TaskSetMagager進行排序,因爲Pool和TaskSetMagager都繼承了Schedulable特質,因此使用相同的排序算法。
排序過程的比較是基於Fair-share來比較的,每個要排序的對象包含三個屬性: runningTasks值(正在運行的Task數)、minShare值、weight值,比較時會綜合考量runningTasks值,minShare值以及weight值。
注意,minShare、weight的值均在公平調度配置文件fairscheduler.xml中被指定,調度池在構建階段會讀取此文件的相關配置。

  1. 如果A對象的runningTasks大於它的minShare,B對象的runningTasks小於它的minShare,那麼B排在A前面;(runningTasks比minShare小的先執行)
  2. 如果A、B對象的runningTasks都小於它們的minShare,那麼就比較runningTasks與minShare的比值(minShare使用率),誰小誰排前面;(minShare使用率低的先執行)
  3. 如果A、B對象的runningTasks都大於它們的minShare,那麼就比較runningTasks與weight的比值(權重使用率),誰小誰排前面。(權重使用率低的先執行)
  4. 如果上述比較均相等,則比較名字。
    整體上來說就是通過minShare和weight這兩個參數控制比較過程,可以做到讓minShare使用率和權重使用率少(實際運行task比例較少)的先運行。
    FAIR模式排序完成後,所有的TaskSetManager被放入一個ArrayBuffer裏,之後依次被取出併發送給Executor執行。
    從調度隊列中拿到TaskSetManager後,由於TaskSetManager封裝了一個Stage的所有Task,並負責管理調度這些Task,那麼接下來的工作就是TaskSetManager按照一定的規則一個個取出Task給TaskScheduler,TaskScheduler再交給SchedulerBackend去發到Executor上執行。

本地化調度

DAGScheduler切割Job,劃分Stage, 通過調用submitStage來提交一個Stage對應的tasks,submitStage會調用submitMissingTasks,submitMissingTasks 確定每個需要計算的 task 的preferredLocations,通過調用getPreferrdeLocations()得到partition 的優先位置,由於一個partition對應一個task,此partition的優先位置就是task的優先位置,對於要提交到TaskScheduler的TaskSet中的每一個task,該task優先位置與其對應的partition對應的優先位置一致。

從調度隊列中拿到TaskSetManager後,那麼接下來的工作就是TaskSetManager按照一定的規則一個個取出task給TaskScheduler,TaskScheduler再交給SchedulerBackend去發到Executor上執行。前面也提到,TaskSetManager封裝了一個Stage的所有task,並負責管理調度這些task。

根據每個task的優先位置,確定task的Locality級別,Locality一共有五種,優先級由高到低順序:

名稱 解析
PROCESS_LOCAL 進程本地化,task和數據在同一個Executor中,性能最好。
NODE_LOCAL 節點本地化,task和數據在同一個節點中,但是task和數據不在同一個Executor中,數據需要在進程間進行傳輸。
RACK_LOCAL 機架本地化,task和數據在同一個機架的兩個節點上,數據需要通過網絡在節點之間進行傳輸。
NO_PREF 對於task來說,從哪裏獲取都一樣,沒有好壞之分。
ANY task和數據可以在集羣的任何地方,而且不在一個機架中,性能最差。

在調度執行時,Spark調度總是會盡量讓每個task以最高的本地性級別來啓動,當一個task以X本地性級別啓動,但是該本地性級別對應的所有節點都沒有空閒資源而啓動失敗,此時並不會馬上降低本地性級別啓動而是在某個時間長度內再次以X本地性級別來啓動該task,若超過限時時間則降級啓動,去嘗試下一個本地性級別,依次類推。

可以通過調大每個類別的最大容忍延遲時間,在等待階段對應的Executor可能就會有相應的資源去執行此task,這就在在一定程度上提到了運行性能。

失敗重試與黑名單機制

除了選擇合適的Task調度運行外,還需要監控Task的執行狀態,前面也提到,與外部打交道的是SchedulerBackend,Task被提交到Executor啓動執行後,Executor會將執行狀態上報給SchedulerBackend,SchedulerBackend則告訴TaskScheduler,TaskScheduler找到該Task對應的TaskSetManager,並通知到該TaskSetManager,這樣TaskSetManager就知道Task的失敗與成功狀態,對於失敗的Task,會記錄它失敗的次數,如果失敗次數還沒有超過最大重試次數,那麼就把它放回待調度的Task池子中,否則整個Application失敗。
失敗重試與黑名單機制-模塊交互過程
在記錄Task失敗次數過程中,會記錄它上一次失敗所在的Executor Id和Host,這樣下次再調度這個Task時,會使用黑名單機制,避免它被調度到上一次失敗的節點上,起到一定的容錯作用。黑名單記錄Task上一次失敗所在的Executor Id和Host,以及其對應的“拉黑”時間,“拉黑”時間是指這段時間內不要再往這個節點上調度這個Task了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章