簡介
前面我分享了一個spark的wordcount,那麼這篇blog我就簡單的介紹一下spark提交任務的流程。
也就是當我們提交一個jar包到集羣的時候,是如何進行調度和計算的。
然後就是分享一下有關RDD 的東西。RDD是spark框架中的組成單位,也是spark分佈式計算的核心,在我看來,spark分佈式計算完全是由RDD來實現的,所以RDD對於學習spark來說是非常關鍵的。
提交jar任務的流程
(1)spark集羣與客戶端的關係
首先,我們要是知道spark集羣和客戶端是分開的。大致的邏輯是從客戶端提交任務給到集羣。但是其中有一些細節大家要注意一下。
(2)客戶端
客戶端上有一個driver程序,顧名思義,他就是我們啓動spark計算任務的啓動的起點。相當於spark-shell或者spark-submit。
(3)集羣
這裏的集羣是一個分佈式的主從結構,一定會有一個master節點,然後會有若干個從節點我們叫worker。
(4)流程
- 首先我們通過Driver提交任務,而driver通過啓動一個SparkContext對象提交任務的請求,請注意這裏並不會提交任務,只是申請master是否執行。
- master節點接受到請求,然後爲這個任務分配資源,然後再將這些資源分配給從節點。
- 然後worker爲此啓動Executor
- 然後Driver開始提交真正的任務而不再只是請求,而這次提交是不經過master的,而是直接提交給worker的。
注:在第四步 的提交的過程中,並不是一次性都提交完成,而是一個stage一個stage來提交的。
但是什麼是stage呢?
Stage
這是每個spark任務被劃分成的單位,每一個stage都可能產生不同的RDD,然後第n個Stage依賴於第n-1個stage的輸出結果。
那麼如何區分stage我們還需要先引入RDD的概念,然後才能講清楚。
RDD
RDD(Resilient Distributed Dataset)叫做彈性分佈式數據集,他是最基本的數據抽象。
RDD允許用戶在執行多個查詢時顯式地將工作集緩存在內存中,後續的查詢能夠重用工作集,這極大地提升了查詢速度。
RDD的屬性,這裏是源碼中的描述:
- 一組分片:對於RDD來說,每個分片都會被一個計算任務處理,並決定並行計算的粒度。用戶可以在創建RDD時指定RDD的分片個數,如果沒有指定,那麼就會採用默認值。
- 計算每個分區的函數:Spark中RDD的計算是以分片爲單位的,每個RDD都會實現compute函數以達到這個目的。
- 依賴關係:RDD的每次轉換都會生成一個新的RDD,所以RDD之間就會形成類似於流水線一樣的前後依賴關係。
- Partitioner代表RDD的分片函數:Partitioner函數不但決定了RDD本身的分片數量,也決定了parent RDD Shuffle輸出時的分片數量。
- 一個列表:存儲存取每個Partition的優先位置(preferred location)。對於一個HDFS文件來說,這個列表保存的就是每個Partition所在的塊的位置。按照“移動數據不如移動計算”的理念,Spark在進行任務調度的時候,會儘可能地將計算任務分配到其所要處理數據塊的存儲位置。
這裏我們可以通過畫圖更加直觀的來理解:
比如我們創建一個RDD
var rddTest = sc.parallelize(Array(,1,2,3,4,5),2)
這樣我就創建了一個RDD,然後是一個1-5的數組,並且分爲了兩個partitioner。
完全印證了彈性和分佈式這兩種特點。
RDD依賴
一個RDD和另一個RDD有兩種依賴的關係:
(1)窄依賴
也就是每一個父RDD 的partition最多被子RDD的一個partition使用
(一對一)
(2)寬依賴
也就是每一個父RDD 的partition被多個子RDD的一個partition使用
(一對多)
根據RDD的依賴來劃分stage
總結起來就是,根據寬依賴劃分Stage。
比如:
兩個RDD之間是窄依賴,那麼這兩個RDD是同屬於一個stage。以此類推。
如果兩個RDD之間是寬依賴,那麼他們一定屬於不同的stage。以此類推。