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聚合函數操作較多。手動重試任務後仍然報錯。
檢視任務報錯日志

分析關鍵資訊
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操作較多。
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倍較為合理。可以參考官網的定義說明:
延伸拓展
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的數量過多,任務執行速度過慢。
job和stage以及task的關系如下圖所示,job的劃分是action操作造成的,Stage是job通過依賴關系劃分出來的,一個Stage對應一個TaskSet,一個Task對應一個rdd分區。同時大量使用shuffle操作也會使task數量變多。
本次優化主要是結合實際優化案例,對底層引擎spark的參數進行調優。如何通過優化提升任務執行效率?如何利用監控分析将被動運維轉為主動運維?請關注後續Hive性能優化及監控方面的實踐連載。