Spark比Hadoop快的緣由:Hadoop在MapReduce後會將結果寫入磁盤,第二次MapReduce再取出,Spark去除了兩次運算間多餘的IO消耗,直接將數據緩存在內存中。html
提交做業->啓動Driver進程->申請資源,即Executor進程->做業代碼分拆爲stage執行->從上一次stage拉取所需key執行,直至任務完成->保存到Executor進程的內存或磁盤web
咱們使用spark-submit提交一個Spark做業以後,這個做業就會啓動一個對應的Driver進程。根據你使用的部署模式(deploy-mode)不一樣,Driver進程可能在本地啓動,也可能在集羣中某個工做節點上啓動。而Driver進程要作的第一件事情,就是向集羣管理器(能夠是Spark Standalone集羣,也能夠是其餘的資源管理集羣,美團•大衆點評使用的是YARN做爲資源管理集羣)申請運行Spark做業須要使用的資源,這裏的資源指的就是Executor進程。YARN集羣管理器會根據咱們爲Spark做業設置的資源參數,在各個工做節點上,啓動必定數量的Executor進程,每一個Executor進程都佔有必定數量的內存和CPU core。緩存
在申請到了做業執行所需的資源以後,Driver進程就會開始調度和執行咱們編寫的做業代碼了。Driver進程會將咱們編寫的Spark做業代碼分拆爲多個stage,每一個stage執行一部分代碼片斷,併爲每一個stage建立一批Task,而後將這些Task分配到各個Executor進程中執行。Task是最小的計算單元,負責執行如出一轍的計算邏輯(也就是咱們本身編寫的某個代碼片斷),只是每一個Task處理的數據不一樣而已。一個stage的全部Task都執行完畢以後,會在各個節點本地的磁盤文件中寫入計算中間結果,而後Driver就會調度運行下一個stage。下一個stage的Task的輸入數據就是上一個stage輸出的中間結果。如此循環往復,直到將咱們本身編寫的代碼邏輯所有執行完,而且計算完全部的數據,獲得咱們想要的結果爲止。網絡
Spark是根據shuffle類算子來進行stage的劃分。若是咱們的代碼中執行了某個shuffle類算子(好比reduceByKey、join等),那麼就會在該算子處,劃分出一個stage界限來。能夠大體理解爲,shuffle算子執行以前的代碼會被劃分爲一個stage,shuffle算子執行以及以後的代碼會被劃分爲下一個stage。所以一個stage剛開始執行的時候,它的每一個Task可能都會從上一個stage的Task所在的節點,去經過網絡傳輸拉取須要本身處理的全部key,而後對拉取到的全部相同的key使用咱們本身編寫的算子函數執行聚合操做(好比reduceByKey()算子接收的函數),這個過程就是shuffle。多線程
當咱們在代碼中執行了cache/persist等持久化操做時,根據咱們選擇的持久化級別的不一樣,每一個Task計算出來的數據也會保存到Executor進程的內存或者所在節點的磁盤文件中。併發
所以Executor的內存主要分爲三塊:第一塊是讓Task執行咱們本身編寫的代碼時使用,默認是佔Executor總內存的20%;第二塊是讓Task經過shuffle過程拉取了上一個stage的Task的輸出後,進行聚合等操做時使用,默認也是佔Executor總內存的20%;第三塊是讓RDD持久化時使用,默認佔Executor總內存的60%。分佈式
Task的執行速度是跟每一個Executor進程的CPU core數量有直接關係的。一個CPU core同一時間只能執行一個線程。而每一個Executor進程上分配到的多個Task,都是以每一個Task一條線程的方式,多線程併發運行的。若是CPU core數量比較充足,並且分配到的Task數量比較合理,那麼一般來講,能夠比較快速和高效地執行完這些Task線程。ide
RDD分佈式是什麼意思?函數
一個RDD,在邏輯上抽象地表明瞭一個HDFS文件;它其實是被分爲多個存放在spark不一樣節點上的分區。好比說,RDD有900萬數據。分爲9個partition,9個分區。oop
RDD彈性是什麼意思,體如今哪一方面? 容錯性體如今哪方面?
a.RDD自動進行內存和磁盤之間權衡和切換的機制,就是RDD的彈性的特色所在。b.當它發現本身的數據丟失,會自動從本身來源的數據進行重計算,這一切對用戶是徹底透明的。
shuffle是劃分DAG中stage的標識,同時影響 Spark 執行速度的關鍵步驟。以下 DAG 流程圖中,分別讀取數據,通過處理後 join 2個 RDD 獲得結果:
RDD 的Transformation函數中,又分爲窄依賴(narrow dependency)和寬依賴(wide dependency)的操做.窄依賴跟寬依賴的區別是是否發生shuffle(洗牌) 操做.寬依賴會發生shuffle操做. 窄依賴是子 RDD的各個分片(partition)不依賴於其餘分片,可以獨立計算獲得結果,寬依賴指 RDD 的各個分片會依賴於父RDD 的多個分片,因此會形成父 RDD 的各個分片在集羣中從新分片。例子:
// Map: "cat" -> c, cat val rdd1 = rdd.Map(x => (x.charAt(0), x)) // groupby same key and count val rdd2 = rdd1.groupBy(x => x._1). Map(x => (x._1, x._2.toList.length))
第一個Map操做將 RDD 裏的各個元素進行映射, RDD 的各個數據元素之間不存在依賴,能夠在集羣的各個內存中獨立計算,也就是並行化,第二個 groupby以後的 Map 操做,爲了計算相同 key 下的元素個數,須要把相同 key 的元素彙集到同一個 partition 下,因此形成了數據在內存中的從新分佈,即 shuffle 操做.shuffle 操做是 spark中最耗時的操做,應儘可能避免沒必要要的 shuffle.
參數調優建議:若是Spark做業中的RDD持久化操做較少,shuffle操做較多時,建議下降持久化操做的內存佔比,提升shuffle操做的內存佔比比例,避免shuffle過程當中數據過多時內存不夠用,必須溢寫到磁盤上,下降了性能。此外,若是發現做業因爲頻繁的gc致使運行緩慢,意味着task執行用戶代碼的內存不夠用,那麼一樣建議調低這個參數的值。
***
http://blog.csdn.net/ap0810217/article/details/55195962
https://tech.meituan.com/spark-tuning-basic.html
http://blog.csdn.net/databatman/article/details/53023818