Hive和Spark SQL優化

優化步驟

  • 問題定位,通過日誌和代碼分析,定位任務耗時長的原因

    • hive任務,對於hive任務,可以通過日誌查看哪個application、以及是哪個階段耗時較長,另外,可以通過stage編號,結合explain查看執行計劃,可以得知耗時較長的application對應的是sql中的哪個操作,便於具體分析原因。如果是map階段較長,很可能是併發不夠,如果是reduce較長,且長時間留停在99%,則很可能發生了數據傾斜,如果是map和reduce的耗時都不長,但整個application的耗時卻很長,則很有可能是大量小文件的讀寫造成的I/O耗時較長,當然,也不排除集羣本身的一些因素,比如網絡等問題。

    • spark任務,對於spark任務,可以在spark UI頁面上查看作業的dag圖,每個stage耗費的時長,每個stage啓有的executor數量,每個任務耗費的時長,最長任務耗時,最短任務耗時,以及任務的中位數耗時等等,通過這些信息,我們可以判斷出當前作業耗時較長的原因。

  • 對症下藥
    大多數情況,運行慢的原因很可能是並行度不夠,或者數據處理發生了傾斜,找到任務耗時長的根源之後,根據不同的原因,作出相應的調優策略,例如,如果是併發不夠,則適當提高併發,如果是數據發生傾斜,則考慮如何解決傾斜。

優化策略

  • 剪枝
  • 提高並行度
  • join優化
  • 避免生成太多小文件
  • 數據傾斜
  • 儘量減少shuffle

剪枝

  • 合理利用分區
    對於全量計算的表,最好考慮拆分,減少數據輸入量

  • 合理利用分桶

    https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL+BucketedTables

  • 謂詞下推,能減少處理的數據,就儘量提前減少,保證數據準確性的前提下,儘量使用謂詞下推操作

    注意:有些條件放在on後和where後結果不一樣,需要留意

    Join(inner join) Left Outer Join Right Outer Join Full Outer Join
    Left Table Right Table Left Table Right Table Left Table Right Table Left Table Right Table
    Join Predicate Pushed Pushed Not Pushed Pushed Pushed Not Pushed Not Pushed Not Pushed
    Where Predicate Pushed Pushed Pushed Not Pushed Not Pushed Pushed Not Pushed Not Pushed

提高並行度

  • 對於hive程序,可以調整提高map或reduce的任務的個數,從而一定程度上提高並行度
    具體調整方法可參考:Hive中Map任務和Reduce任務數計算原理

  • 對於可以併發執行的,可以設置併發,讓多個沒有依賴關係的application併發執行,配置如下:
    set hive.exec.parallel=true

  • 對於spark程序,可以適當調整提高executor的數量

Join優化

  • 對於hive作業,有小表或比較小的表,儘量走mapjoin

    set hive.auto.convert.join=true; -- 版本0.11.0之後,默認是開啓狀態的,但猛獁時不時會把這個配置關閉,比較坑,所以最好還是手動配置一下
    set hive.mapjoin.smalltable.filesize = 25000000; -- 默認是25Mb開啓mapjoin,對於稍微超過這大小的,可以適當調大,但不能太大
    

    另外,對於join操作中有子查詢,且子查詢中的某個表原始數據大於25M,但經過子查詢之後,數據量小於25M的,可以採用臨時表落地的方式,讓此join走mapJoin,如果不落地,暫時無法走mapJoin,spark中,自適應框架中加入這個feature,自動判別,但目前還未上線。

  • 對於spark作業,如果join時有小表的情況,儘量走broadcasthashjoin,該默認是開啓的,小表大小默認10M,如果小表小於10M,但仍然沒有走broadcasthashjoin,可以檢查一下相關配置參數。

spark.sql.autoBroadcastJoinThreshold,默認值:10485760(10MB),但要注意,只支持運行了ANALYZE TABLE <tableName> COMPUTE STATISTICS noscan命令的hive元數據表,所以,如果是剛剛創建的表想走broadcasthashjoin,還需要運行一下此條命令。

BroadcastHashJoin:spark 如果判斷一張表存儲空間小於 broadcast 閾值時(Spark 中使用參數 spark.sql.autoBroadcastJoinThreshold 來控制選擇 BroadcastHashJoin 的閾值,默認是 10MB),就是把小表廣播到 Executor, 然後把小表放在一個 hash 表中作爲查找表,通過一個 map 操作就可以完成 join 操作了,避免了性能代碼比較大的 shuffle 操作,不過要注意, BroadcastHashJoin 不支持 full outer join, 對於 right outer join, broadcast 左表,對於 left outer join,left semi join,left anti join ,broadcast 右表, 對於 inner join,那個表小就 broadcast 哪個。

  • 小文件問題

    大量的小文件不僅會給namenode增加壓力,也極易產生數據性能問題

    • 對於hive作業

    對於有產生很多小文件的任務,尤其是動態分區,可以通過以下配置,在任務結束自動合併小文件
    set hive.merge.mapfiles = true; – 開啓map端合併小文件,默認開啓,會另外運行一個只有map的applicaiton來合併小文件
    set hive.merge.mapredfiles = true; – 開啓reduce端合併小文件
    set hive.merge.smallfiles.avgsize = 16000000 – 平均文件大小,默認16M,滿足條件則自動合併,只有在開啓以上兩個開關纔有效

    • 對於spark作業

    如果每個分區很小,但產生的文件很多,可以在sql最後加上以下,來合併同一個分區(ds)裏的多個小文件:

    distribute by ds
    
  • 存儲格式
    儘量不要使用text文件存儲,不僅存儲量大,還可能引發bug,例如文本存儲的時候,如查某個字段的值存在\n換行符時,在數據讀取時就會有異常。

  • 傾斜問題

    如果是傾斜問題,可參考文章:

  • 減少shuffle次數

    shuffle會造成數據在集羣中傳輸,並且伴隨着讀和寫,很影響任務的執行性能

    unionunion allunion去重,有shuffle,union all不去重,無shuffle
    儘量使用union all,例如有以下sql:

    select c1, c2
    from (
    	select c1, c2 from t1
    	union
    	select c1, c2 from t2
    	union
    	select c1, c2 from t3
    ) t4
    

    可換成以下,將兩次shuffle降低到一個shuffle

    select c1, c2
    from (
    	select c1, c2 from t1
    	union all
    	select c1, c2 from t2
    	union all
    	select c1, c2 from t3
    ) t4
    group by c1, c2
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章