大數據

技本功|Hive優化之Spark執行引擎參數調優(二)

Hive是大數據領域常用的組件之一,主要是大數據離線數倉的運算,關於Hive的性能調優在日常工作和麵試中是經常涉及的的一個點,因此掌握一些Hive調優是必不可少的一項技能。影響Hive效率的主要有數據傾斜、數據冗餘、job的IO以及不同底層引擎配置情況和Hive本身參數和HiveSQL的執行等因素。本文主要結合實際業務情況,在使用Spark作為底層引擎時,通過一些常見的配置參數對報錯任務進行調整優化。

下面從兩個方面對複雜任務的優化:

Spark資源參數優化
主要針對Spark運行過程中各個使用資源的地方,通過調節資源相關參數,來優化資源使用的效率,從而提升Spark作業的執行性能。例如:num-executors、executor-memory、executor-cores等。

Shuffle相關參數調優
主要針對spark運行過程中的shuffle,通過調節參數,提高shuffle的執行效率,從而提升spark作業的執行性能。例如:spark.shuffle.memoryFraction,spark.sql.shuffle.partitions等。

案例1
複雜任務執行失敗,大約有400行sql,較為複雜,join聚合函數操作較多。手動重試任務後仍然報錯。

查看任務報錯日誌
image.png

分析關鍵信息

Exception in thread "broadcast-exchange-0" java.lang.OutOfMemoryError: Not enough memory to build and broadcast the table to all worker nodes. As a workaround, you can either disable broadcast by setting 
spark.sql.autoBroadcastJoinThreshold to -1 or increase the spark driver memory by setting spark.driver.memory to a higher value

得出結論
當前所有的工作節點均沒有足夠的內存去build並且廣播表,建議處理方法:將廣播置為無效或者增加spark的driver memory。

優化效果
經過對比測試驗證,在同時調大excutor內存和driver內存後,任務可以成功運行。單獨調大driver或excutor內存,任務運行依然失敗。

Q1:什麼情況下應將廣播設置為無效?
根據官網文檔對該參數的描述可知:其默認值為10M,意味著執行join時,這張表字節大小在10M內可以自動廣播到所有工作節點。將表廣播到其他工作節點,會減少shuffle的過程,提升效率。如果在內存足夠並且數據量過多的情況下,可以將適當提高該參數值作為一種優化手段。如果在表都很大的情況下,建議將自動廣播參數置為無效。將參數值設置為-1時會禁用自動廣播。

案例2
某個任務已經運行了40多個小時,自動重試了3次,一直處於阻塞狀態。

查看異常任務SQL
發現任務中由10多個SQL語句構成,一個語句大概有200+行,union all、join、sum操作較多。
image.png

查看任務報錯日誌
image.png

分析關鍵信息

org.apache.spark.shuffle.MetadataFetchFailedException: 
Missing an output location for shuffle 433

得出結論
一般任務有大量shuffle操作的時候,我們可以從shuffle數據量及shuffle分區數的角度對任務進行優化調整。

優化效果
只採取調大executor內存的方式進行優化,任務可以運行成功,但任務執行耗時仍然需20+分鐘,執行效率與優化前相比無明顯變化。原因在於任務執行中產生了較多的task,此時可以通過調整分區參數進行深入優化。分區參數spark.sql.shuffle.partitions是Spark SQL專用的設置,將該參數的值由200(默認值)調小為50,任務運行成功,執行耗時減少50%,約10分鐘;繼續將該參數調小為10,任務運行成功,執行耗時減少70%,約6分鐘,優化完成。

**Q2:spark.default.parallelism參數與
spark.sql.shuffle.partitions參數有什麼區別?**

雖然這兩個參數較為相似,但default.parallelism只在處理RDD時才會起作用,對Spark SQL無效。其值設置為【num- executors * executor-cores】的2~3倍較為合理。可以參考官網的定義說明:
image.png

延伸拓展
1.shuffle分為shuffle write和shuffle read兩部分。

2.shuffle write的分區數由上一階段的RDD分區數控制,shuffle read的分區數則是由Spark提供的一些參數控制。

3.shuffle write可以簡單理解為類似於saveAsLocalDiskFile的操作,將計算的中間結果按某種規則臨時放到各個executor所在的本地磁盤上。

4.shuffle read時數據的分區數則是由spark提供的一些參數控制。如果這個參數值設置的很小,同時shuffle read的量很大,那麼將會導致一個task需要處理的數據非常大,容易引發JVM crash。如果這個參數值設置的很大,可能會導致task的數量過多,任務執行速度過慢。
image.png

job和stage以及task的關係如下圖所示,job的劃分是action操作造成的,Stage是job通過依賴關係劃分出來的,一個Stage對應一個TaskSet,一個Task對應一個rdd分區。同時大量使用shuffle操作也會使task數量變多。
image.png

本次優化主要是結合實際優化案例,對底層引擎spark的參數進行調優。如何通過優化提升任務執行效率?如何利用監控分析將被動運維轉為主動運維?請關注後續Hive性能優化及監控方面的實踐連載。
image.png

Leave a Reply

Your email address will not be published. Required fields are marked *