Hivesql優化&sparksql優化梳理

Hive sql 優化方案梳理總結

目錄

Hive sql 優化方案梳理總結

說明

簡單最合理

對應表的HDFS文件大小和數量問題

數據傾斜問題

where在on前面後面的問題


 


說明

此篇文章我們將對Hivesql的優化方案進行梳理和總結,歡迎大家一起討論,可以補充和完善的地方歡迎各位大牛積極在評論區提出,大家一起共同學習共同成長

簡單最合理

這個是我個人的習慣,能實現的情況下最簡單的就是最好的,邏輯sql不要寫的過複雜,越簡單越好

對應表的HDFS文件大小和數量問題

很多在寫sql的時候不關心表對應的HDFS路徑下小文件數量的問題,其實要寫高效的sql必須要關注文件大小和數量情況

  • 文件過小,數據量過多
    • 一般會出現的問題
      • 文件數量越多在執行sql的時候可能會啓更多的mr任務,耗費更多的cpu core,尤其是在join的時候會導致啓動大量的的mr任務和耗費非常多的core,在job計算完成後同樣會使用大量的cpu資源去落地HDFS,比如某個任務在計算完成之後產生了20w個文件,那麼在落地hdfs的時候意味着需要20w個core去寫hdfs,會導致集羣所有的資源去做這件事情,在此期間就會導致spark thrift server 無法提交任務,會頻繁出現OOM或者timeout的情況,對hdfs的namenode讀寫也會帶來很大的負面影響,增加namenode rpc 響應時間降低hadoop的讀寫效率
      • 下游job同樣會產生大量的小文件,惡性循環,導致文件數量越來越多
      • 如果任務非正常執行完成,產生的中間文件.hive文件不會自行刪除,這個文件可能會很大,小文件數量可能也會非常多浪費集羣資源
    • 解決方案
      •     文件務必設置壓縮
           
        基於TEXTFILE進行gzip壓縮(文件大小按需調整)
                         
        set mapred.max.split.size=256000000 ;
        set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat ;
        set hive.merge.mapfiles = true ;set hive.merge.mapredfiles= true ;
        set hive.merge.size.per.task = 256000000 ;
        set hive.merge.smallfiles.avgsize=256000000 ;
        set hive.exec.compress.output=true; set mapreduce.output.fileoutputformat.compress=true ;
        set mapreduce.output.fileoutputformat.compress.type=BLOCK ;
        set mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.GzipCodec ;
        set hive.exec.dynamic.partition.mode=nonstrict;
        set hive.hadoop.supports.splittable.combineinputformat=true;
        
        
        基於ORC進行合併snnapy壓縮(文件大小按需調整)
        set mapred.min.split.size.per.node=7000000000;
        set mapred.min.split.size.per.rack=7000000000;
        set mapred.max.split.size=7000000000;
        set hive.merge.smallfiles.avgsize=6000000000;
        set hive.merge.size.per.task=6000000000;
        set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat ;
        set hive.merge.mapfiles=trueset hive.merge.mapredfiles=true;
        set hive.exec.compress.output=true;set mapreduce.output.fileoutputformat.compress=true ;
        set hive.exec.dynamic.partition.mode=nonstrict;set hive.exec.dynamic.partition=true;
  • 文件過大
    • 一般會出現的問題
      • 個別分區文件過大,其他分區文件很小很容易出現數據傾斜情況
      • 單文件過大,一般進行spark shuffle的時候一個文件對應一個core,如果文件過大經常出現一個線程無法按時完成分析任務的情況
    • 解決方案
      • 均勻打散文件,把一個大文件拆分成幾個較小的文件,以便能分配更多的core去並行計算,提高並行度,併合理設置 spark.sql.shffule.partition參數值,如果文件數量過多,而這個值設置的特別小也是無濟於事
        set spark.sql.shuffle.partitions=n;
        ---n代表需要打散成幾個文件
        INSERT overwrite TABLE table_a Select * from table_a distribute by rand()
      • 調整計算資源大小

        --調整hive
        # map 任務內存總大小
        set mapreduce.map.memory.mb=4096
        # map 堆大小
        set mapreduce.map.java.opts=-Xmx3072m;
        set mapreduce.reduce.memory.mb=8192;
        set mapreduce.reduce.java.opts=-Xmx2048m;
        --調整spark
        --調整executor的memory大小
        SPARK_EXECUTOR_MEMORY="18G" #Memory per Worker (e.g. 1000M, 2G) (Default: 1G)
        --調整executor的core數量
        SPARK_EXECUTOR_CORES="6"
        --調整executor的數量
        spark.dynamicAllocation.initialExecutors 60
        spark.dynamicAllocation.maxExecutors 100
        spark.dynamicAllocation.minExecutors 60
        --調整spark driver memory的大小
        SPARK_DRIVER_MEMORY="48G" #Memory for Master (e.g. 1000M, 2G) (Default: 512 Mb)

         

  • 數據傾斜問題

    • 說明 在數據ETL中,數據傾斜一直以來是個討論高頻的問題,尤其是在集羣規模比較大的集羣,數據量越大,發生的機率越高,一般來說最常見的表現就是hive mr任務或者spark task中 大部分任務已經succeed,但是剩下很少的幾個mr任務或者 spark task仍需要執行很長的時間,或者根本執行不完,這種情況原因也比較簡單,就是某個分區的一個分區數據量過大,或者某一個分區內文件分佈不均勻,有的文件很大,有的文件很小,導致分配到處理這個文件的task需要耗費很長的時間去處理,這種情況下,入股分析邏輯裏再加個複雜的udf,整上個3個if的邏輯,那這個任務幾乎很難跑完了
    • 常用的解決方案 我個人覺得在解決數據傾斜情況沒有一個特定的方案,不過我們方向是唯一的,我們需要把較大的數據均勻的分配到不同的task中去。
      • 將大文件打散上面已有說明,並設置spark.sql.shuffle.partitions 設置spark的並行度
      • 廣播小表變量,當大表與小表進行join的時候,將小表作爲變量廣播,把之前的shuffle轉化爲本地的map階段處理,在一定程度上也會緩解
  • where在on前面後面的問題

    請參考此鏈接
  • 數倉邏輯層面的優化

    • 有些場景ODS層明細數據可能比較集中,比方說如果所有設備和業務的數據都上報到了同一個表裏,再拆分不同業務的數據到各自的業務表的時候,如果數據規模很大(ods總表每天幾千個文件,每個文件壓縮完300M+),設備種類多(100+),每個業務每個設備的數據都要起一個各自的流程去掃描ods總表去拉取各自需要的數據,那麼意味着這幾千個大文件會被所有這些sql都掃描一遍,很浪費資源,爲此我們可以對ods總表做初步的拆分,ods總表->ods_分表1,ods_分表2,ods_分表3->ods_each_product表,這樣會穩定很多,避免了資源擁堵情況
    • 從大局考慮,如果sql job多的情況,定時任務儘量安排到凌晨到早上之前,白天的時間段內的計算資源主要用於日常的開發和日常臨時需求的交互式查詢,資源得到合理有效利用
    • 對於不同業務數據品類繁多而需要同時複雜計算(例如窗口函數比較複雜的計算),這種情況我們一般會設計二級分區作爲不同業務的標識(不建議使用二級以上的hive 分區,因爲分區等級越多,會導致分區數量越大,這樣會給hive metastore 帶了很大的壓力,在hdfs落地的時候也會有很大的壓力),這種情況下如果不同業務的數據量差距很多,建議針對不同的業務分區採取不同的業務優化方案,比如根據不同業務的數據規模把job 分拆成大中小三類,如果是使用hive進行分析,我們就分配不同的map reduce 堆內存,如果是spark 我們就設置不同的並行度,當然針對數據量規模大的業務數據我們可以提前進行拆分,比如將每個256M的文件拆成5個50M左右的文件,這樣分配到每個task的時候就能執行的快一些
  • group by代替COUNT(DISTINCT)

    在很多時候好多同學喜歡直接用count(distinct c1)用於數據統計,但是這個的計算效率遠遠不如group by,尤其是在數據量很大的時候,數據量小的時候就無所謂了,count(distinct c1)這個函數一般只啓用一個reduce task 去計算,效率很低,但是group by不會,在公司好幾次有些人使用count(distinct c1)算很久算不出想要的結果值,還進行了投訴,但是我們告訴他們換成 select c1, count(c1) as cnt from tab group by c1 之後很快得出了結果
  • 儘量不要使用in這種函數

  • case when函數when越多算的越慢

    表中的文件都需要走一遍when流程,when越多效率就越低,而且在reduce階段最好做一遍合併壓縮操作,否則可能會產生很多文件

 

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