Spark 任務性能優化淺談

1 spark on yarn(cluster模式)框架

                                                                                             圖1- 1

1.1 yarn組件概念

ResourceManager:負責集羣的資源管理和分配。

NodeManager:每個節點的資源和任務管理器。

Application Master:YARN中每個Application對應一個AM進程,負責與RM協商獲取資源,獲取資源後告訴NodeManager爲其分配並啓動Container。

Container:YARN中的抽象資源。

1.2 spark組件概念

Driver:進行資源申請、任務分配並監督其運行狀況等。

DAGScheduler:將spark job轉換成DAG圖。

TaskScheduler:負責任務(task)調度

2 spark shuffle

2.1 窄依賴與寬依賴

理解shuffle之前,需要先理解窄依賴和寬依賴。

    窄依賴:父RDD的每個分區都只被子RDD的一個分區依賴  例如map、filter、union等操作會產生窄依賴。

    寬依賴:父RDD的分區被子RDD的多個分區依賴   例如 groupByKey、reduceByKey、sortByKey等操作會產生寬依賴,會產生shuffle過程,也是劃分stage依據。

                                                                                        圖2- 1

2.2 Shuffle過程

                                                                                               圖2- 2

    Shuffle過程包括:shuffle write與shuffle read。

    Shuffle write:在stage n-1內,每個task經過一系列算子處理後,將數據按key進行分類寫入相應磁盤文件中,相同key會被寫到同一個磁盤文件中。

    Shuffle read:stage n中每個task進行運算前,需要從上游stage n-1拉取屬於自己的磁盤文件。

 

疑問:

    a、在shuffle write中,如何決定Block File文件數?

對於產生shuffle過程的算子,有一個參數指定分區數,即shuffle write時Block File文件數。如以reduceByKey爲例,下圖是reduceByKey的python api說明,numPartitions指定shuffle write時Block File文件數,若numPartitions值爲None,則參數spark.default.parallelism決定shuffle write時Block File文件數。

                                                                                        圖2- 3

    b、Block File文件數下游stage有何影響?

在Stage n-1中Shuffle write總數據量是一定的,若Block File文件數較小,則Stage n中每個task處理的數據量較大,在計算資源不變的情況下,容易出現oom;若Block File文件數較大,則Stage n中每個task處理的數據量較小,在計算資源不變的情況下,會出現資源浪費。因此在計算資源不變情況下,合適Block File文件數能充分利用計算資源

    c、如何知道每個stage中shuffle write的數據量?

通過spark web ui查看任務運行過程圖,具體詳看2.3 spark web ui介紹

    d、如何設置合適的分區數,即Block File文件數?

需要根據stage運算過程的計算複雜度而定,若stage n中使用了較多的算子並且運算過程複雜,則在計算資源不變的情況,需要設置較大的分區數;反之設置較小的分區數。

 

Spark性能優化原則之一:根據計算資源,合適設置每個stage中task的處理數據量

2.3 spark web ui介紹

2.3.1 啓動HistoryServer

    對於運行完成的spark任務,可以通過HistoryServer查看運行過程圖。

  1. 如何啓動spark HistoryServer?

在${spark_home}/sbin下,運行start-history-server.sh

  1. 如何查看任務的運行過程圖?

在瀏覽器中輸入啓動HistoryServer的ip以及端口(默認18080),搜索任務的application id即可

2.3.2 spark job

                                                                                          圖2- 4

    Spark任務中,每個Action算子都會生成一個Job,如collect()、count()、first()、saveAsTextFile()、collectAsMap()。

    在圖2-4中可以瞭解到任務有幾個job,以及每個Job的提交時間,運行時長,以及Tasks數等等。

2.3.3 spark stage

                                                                                        圖2- 5

    由圖2-5可以知道每個stage的Shuffle Read數據量、Shuffle Write數據量、Tasks數據量(分區數)。

                                                                                              圖2- 6

    由圖2-6可以知道某個stage中更詳細信息,如每個task的Shuffle Red Size,從而瞭解每個task處理的數據量是否均勻,是否出現數據傾斜

3 spark參數設置與算子優化

3.1 spark參數設置

spark.executor.memory:每個executor擁有的堆內存

spark.yarn.executor.memoryOverhead:每個executor擁有的非堆內存

spark.executor.cores:每個executor擁有的core數量

spark.default.parallelism:設置全局默認的分區數

spark.dynamicAllocation.enabled : 是否允許動態分配Executor數

spark.dynamicAllocation.initialExecutors : 設置初始Executor數

spark.dynamicAllocation.minExecutors :設置最小Executor數

spark.dynamicAllocation.maxExecutors :設置最大Executor數

 

參數設置原則:根據集羣資源情況,合理設置參數。如若集羣資源充足,設置較大內存並且申請更多Executor數,會使任務更快完成;若集羣資源不足,增大分區數(設置spark.default.parallelism或者算子的分區參數),減少每個task處理的數據量,以保證任務完成。

3.2 spark算子優化

算子優化原則:減少shuffle過程,減少算子使用

  1. groupByKey:避免使用groupByKey,採用reduceByKey代替,因爲reduceByKey會進行本地聚合,類似於MapReduce中的combiner
  2. collect:減少使用collect算子
  3. collectAsMap:少使用collectAsMap算子,如果數據量大,採用join算子代替
  4. broadcast:合理使用broadcast,其作用是在每個executor保存一份變量副本,從而避免在每個task中保存一份變量副本
  5. coalesce 與repartition: repartition(numPartitions)等效於

coalesce(numPartitions, shuffle=True)。若需要分區數由多變少,使用coalesce;若每個分區數據量相差較大,可以考慮repartition均勻每個分區數據量,但不一定有效。

6、persist:對重複使用的RDD進行序列化,建議使用方式爲persist(StorageLevel.MEMORY_AND_DISK),避免使用cache()或者persisit()

7、減少算子使用:合併算子,比如rdd.filter().map().filter(),考慮是否可以修改成rdd.map().filter()或者rdd.filter().map()

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