控制map個數與性能調優參數


本系列幾章系統地介紹了開發中Hive常見的用戶配置屬性(有時稱為參數,變量或選項),並說明了哪些版本引入了哪些屬性,常見有哪些屬性的使用,哪些屬性可以進行Hive調優,以及如何使用的問題。以及日常Hive開發中如何進行性能調優。
1.Hive有哪些參數,如何查看這些參數

    Hive自帶的配置屬性列表封裝在HiveConfJava類中,因此請參閱該HiveConf.java文件以獲取Hive版本中可用的配置屬性的完整列表。具體可以下載hive.src通過eclipse查看。全部屬性有上千個吧,一般Hive的自帶屬性都是以hive.開頭的,每個屬性且自帶詳細的描述信息,其次Hive官網也有,但是屬性不是特別全。Hive官方參數網址
    Hive除了自身帶了一些配置屬性,因為其底層使用的是hadoop(HDFS,MR,YARN),所以有些HADOOP的配置屬性Hive也可以使用,進行配置,但是有些則使用不了。比如mapred.max.split.size 就屬於MR的參數,但是hive可以使用。

2.map個數的控制參數與性能調優

     很顯然,對於這個控制每個map的split輸入大小的參數,不是hive自帶的參數,而是MR提供的參數,但是Hive可以通過set的形式配置使用,而且對於調優有很大的作用。但是這個參數實際上要配合HDFS的blocksize一起使用。下面以我們公司開發環境的默認配置參數。

    -- 每個Map最大輸入大小,
    hive> set mapred.max.split.size;
    mapred.max.split.size=256000000  這也是官方默認值
    -- 每個Map最小輸入大小
    hive> set mapred.min.split.size;
    mapred.min.split.size=10000000   這也是官方默認值
    hive> set dfs.block.size;
    dfs.block.size=134217728   我們集群默認hdfs的block塊大小是128Mb,但注意這個參數通過hive設置更改實際沒有用的,只能hdfs設置。

2.1數據准備,兩張表

    如下進行兩張表join,其中每張表的大小,hdfs上存儲的文件總個數,以及每個文件的大小。

    大表總共158749566行,文件總大小4.4G,存儲個數22個文件,每個大小200Mb左右。
    小表總共1979375 行,文件大小50.7Mb,存儲個數2個文件,大小50Mb以內。

    [finance@hadoop-client13-prd ~]$ hadoop fs -du  -h  hdfs://suninghadoop2/user/finance/hive/warehouse/fdm_tmp.db/company_liquidation_fgeics_company_ar_d
    206.7 M  hdfs://suninghadoop2/user/finance/hive/warehouse/fdm_tmp.db/company_liquidation_fgeics_company_ar_d/000000_0.deflate
    .....省略.................
    hdfs://suninghadoop2/user/finance/hive/warehouse/fdm_tmp.db/company_liquidation_fgeics_company_ar_d/000021_0.deflate
    ---------------------------------------------------------------------------------------
    [finance@hadoop-client13-prd ~]$ hadoop fs -du  -h  hdfs://suninghadoop2/user/finance/hive/warehouse/fdm_tmp.db/t_fgeics_company_liquidation_d_tmp
    36.4 M  hdfs://suninghadoop2/user/finance/hive/warehouse/fdm_tmp.db/t_fgeics_company_liquidation_d_tmp/000000_0.deflate
    14.3 M  hdfs://suninghadoop2/user/finance/hive/warehouse/fdm_tmp.db/t_fgeics_company_liquidation_d_tmp/000001_0.deflate

2.2兩個表進行關聯,其中小表在前,大表在后

2.2.1如下,運行如下代碼,實現兩個表進行關聯。

    set mapred.max.split.size=134217728;
    set mapred.min.split.size=134217728;
    drop table IF EXISTS fdm_tmp.company_liquidation_fgeics_company_ar_d_tmp;
    create table fdm_tmp.company_liquidation_fgeics_company_ar_d_tmp
    as
    select
     a.id
    ,a.entid
    ,a.ancheyear
    ,b.liqmen
    ,b.ligprincipal
    ,a.regno
    ,a.tel
    ,a.postalcode
    ,a.dom
    ,a.email
    ,a.busst
    ,a.empnum
    ,a.name
    ,a.updated
    ,b.etl_time
    from fdm_tmp.t_fgeics_company_liquidation_d_tmp  b
    right join fdm_tmp.company_liquidation_fgeics_company_ar_d  a
    on b.entid = a.entid;
     
    Hadoop job information for Stage-1: number of mappers: 24; number of reducers: 17

結果分析:hive啟動了24個map函數,17個reduce函數。在hadoop中,一般默認的split切片小於等於blocksize(128Mb),如果是小文件的話(未進行小文件的合並)則每個小文件啟動一個map函數。而實際在hive中,並不是split的大小要小於等於blocksize,而是可以遠大於blocksize。比如這里,4.4G文件表,按128Mb切片算的話,至少實際需要35個map,而實際只需要24個,平均每個map處理了187Mb的文件。這是為什么呢?此外這里明明設置了set mapred.max.split.size=134217728,每個map最大split塊是 128Mb,而實際為什么參數沒有用呢?網上有很多關於這方面的文章,但是幾乎都是轉載抄襲,沒有任何深入理解,或者深入剖析決定map個數的原因。
3.案例演示決定map個數的因素

       其實決定map個數的因素有很多,比如文件是否壓縮,壓縮的后的文件是否支持切分,比如文件默認的inputfort格式,不同實現類的split算法也不同,那么map的個數調優方式也不同,下面按分類詳細說明hive中決定map個數的因素與常見map調優的使用。
首先分類:處理的文件是否壓縮,且壓縮算法是否支持文件的切分

 如下我們公司,對於hive關於壓縮的配置,使用了壓縮,且使用的是默認的壓縮算法是deflate方法。

    hive>  set io.compression.codecs; --配置了哪些壓縮算法
    io.compression.codecs=org.apache.hadoop.io.compress.GzipCodec,org.apache.hadoop.io.compress.DefaultCodec,com.hadoop.compression.lzo.LzoCodec,com.hadoop.compression.lzo.LzopCodec,org.apache.hadoop.io.compress.BZip2Codec
    hive> set hive.exec.compress.output;
    hive.exec.compress.output=true  --是否開啟壓縮
    hive> set  mapreduce.output.fileoutputformat.compress.codec;  --使用的壓縮算法
    mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.DefaultCodec

我們知道hive中有些壓縮算法是不支持文件切分的,如下我們使用的默認的deflate算法,就不支持文件切分。

 3.1.文件使用了壓縮,且壓縮算法不支持文件切分

    ------------------------使用不同參數執行上面代碼產生的map個數---------------------------------
    --1.使用系統配置的默認值
    set mapred.max.split.size  = 256000000; --
    set mapred.min.split.size = 256000000;
    Hadoop job information for Stage-1: number of mappers: 24; number of reducers: 17
     
    --2.降低系統默認值
    set mapred.max.split.size=134217728;
    set mapred.min.split.size=134217728;
    Hadoop job information for Stage-1: number of mappers: 24; number of reducers: 17
     
    --3.調高系統默認值
    set mapred.max.split.size=500000000;
    set mapred.min.split.size=256000000;
    Hadoop job information for Stage-1: number of mappers: 9; number of reducers: 17
     
    --4.調高系統默認值
    set mapred.max.split.size=1024000000;
    set mapred.min.split.size=1024000000;
    Hadoop job information for Stage-1: number of mappers:6 ; number of reducers: 17

       如上我們使用不同的參數配置,來運行上面同一段代碼,看系統產生的map個數,細心的人會發現,當我們使用默認值是產生了24個map,平均每個map處理了187Mb文件,但當我們調低set mapred.max.split.size=134217728時(每個map最多處理128Mb),相應的map個數並沒有增加,這是為什么呢?

       關於這個問題就要說到決定map個數的首要因素:文件是否啟動壓縮,且壓縮算法是否支持文件切分了。因為這里文件存儲使用默認的deflate算法,不支持文件切分,所以設置的參數split.size=134217728沒有生效。因為每個map處理的splitsize實際上要大於等於每個文件存儲的大小。這里每個文件存儲的大小200Mb左右,所以每個map處理的最小尺寸要大於200Mb。

      而當我們將set mapred.max.split.size=102400000設置的很大時,為什么又可以控制map個數了呢?因為deflate壓縮算法雖然不支持文件切分,但是可以進行文件合並哇。從hive0.5開始就默認map前進行小文件合並了。如下,我們公司使用的也是默認的開啟map前文件合並。但是注意即使這里支持文件合並,也是基於文件塊的整個文件塊合並,而不是基於blocksize的block合並。

    hive> set hive.input.format; --hive0.5開始的默認值,這個值會影響map個數的控制
    hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat

尖叫提示1:

         通過上面分析總結,當hive需要處理的文件是壓縮,且壓縮算法不支持文件切分的時候,決定map個數的因素主要是文件塊實際存儲的大小,如果文件塊本身很大,比如500Mb左右,那么每個map處理的splitsize至少要是500Mb左右。這個時候我們不能人為通過參數降低每個map的splitsize來增加map個數,只能通過增加splitsize,減少map個數。

        但是一般經驗來說,每個map處理的splitsize最好是128Mb(等於blocksize),這樣效率最高。所以這個時候如果我們想增加map個數,只能通過臨時表或者insert ...select的形式,通過參數配置將文件塊重新存儲成較小的文件塊,然后再進行處理。反之,如果文件塊本身很小,那么我們可以通過增加splitsize來減少map,進而調優提高程序的運行效率。
尖叫總結1:

        如果hive處理的文件是壓縮模式,且壓縮模式不支持文件切分,那么這個時候我們只能通過控制參數來減少map個數,而不能通過配置參數來增加map個數,所以Hive對於壓縮不可切分文件的調優有限。可以首先通過hadoop fs -du -s -h命令查看文件的存儲大小結果,然后根據實際進行調優。常用的配置參數如下:

    set hive.input.format = org.apache.hadoop.hive.ql.io.CombineHiveInputFormat; --hive0.5開始就是默認值,執行map前進行小文件合並
    ----------------------------------------------------------------------
    set mapred.max.split.size=256000000  
    set mapred.min.split.size=10000000
    set mapred.min.split.size.per.node=8000000 --每個節點處理的最小split
    set mapred.min.split.size.per.rack=8000000 --每個機架處理的最小slit.
    ------------------------------------------------------------------------
    1.注意一般來說這四個參數的配置結果大小要滿足如下關系。
    max.split.size >= min.split.size >= min.size.per.node >= min.size.per.node
     
    2.這四個參數的作用優先級分別如下
    max.split.size <= min.split.size <= min.size.per.node <= min.size.per.node
     
    比如如下,同樣上面的代碼,我們將其參數設置如下,發現只啟動了12個map,故max.split.size沒有起作用。
    當四個參數設置矛盾時,系統會自動以優先級最高的參數為准,進行計算
    set mapred.max.split.size=300000000;
    set mapred.min.split.size.per.node=300000000;
    set mapred.min.split.size.per.rack=300000000;
    Hadoop job information for Stage-1: number of mappers: 12; number of reducers: 17
     
    3.注意這四個參數可以選擇性設置,可以選擇性設置大小或者使用默認值,但仍遵循前兩條規則。

3.2 文件未使用壓縮,或壓縮算法支持文件切分

        同樣是上面那個4.4g文件,我們這個時候讓其為非壓縮模式,發現這個時候文件總大小為23.4G,存儲為22個文件,平均每個文件大小都在1.1G左右。所以壓縮有時候是個好東西。如下我們所有非壓縮的性能測試基於此文件。

    [finance]$ hadoop fs -count hdfs://suninghadoop2/user/finance/hive/warehouse/fdm_tmp.db/company_liquidation_fgeics_company_ar_d
    1           22        25154158871 hdfs://suninghadoop2/user/finance/hive/warehouse/fdm_tmp.db/company_liquidation_fgeics_company_ar_d
    -----------------------------------------------------------------------------------------------------------------------------------
    [finance]$ hadoop fs -du -s -h hdfs://suninghadoop2/user/finance/hive/warehouse/fdm_tmp.db/company_liquidation_fgeics_company_ar_d
    23.4 G  hdfs://suninghadoop2/user/finance/hive/warehouse/fdm_tmp.db/company_liquidation_fgeics_company_ar_d
    -----------------------------------------------------------------------------------------------------------------------------------
    [finance]$ hadoop fs -du -h hdfs://suninghadoop2/user/finance/hive/warehouse/fdm_tmp.db/company_liquidation_fgeics_company_ar_d
    1.1 G  hdfs://suninghadoop2/user/finance/hive/warehouse/fdm_tmp.db/company_liquidation_fgeics_company_ar_d/000000_0
    1.1 G  hdfs://suninghadoop2/user/finance/hive/warehouse/fdm_tmp.db/company_liquidation_fgeics_company_ar_d/000001_0
    ...............................

3.2.1.若這時set hive.input.format為HiveInputFormat

    hive> set hive.input.format; --從hive0.5就默認是CombineHiveInputFormat,所以這個用的不多
    hive.input.format=org.apache.hadoop.hive.ql.io.HiveInputFormat;

   如果這時set hive.input.format為HiveInputFormat,這個時候有以下三個屬性值來確定InputSplit的個數:

    set mapred.map.tasks=2    --我們公司使用的是默認2
    set mapred.max.split.size=256000000  --我們公司默認值
    set mapred.min.split.size=10000000   ---我們公司默認值
    set  dfs.block.size=134217728   --128Mb
    ----------------------------------------------------------------------------------------
    1. goalSize:該值由 totalSize/numSplits  totlasize文件塊大小,numslplits=mapred.map.tasks=2
    2. minSize:由配置參數 mapred.min.split.size(或者新版本的mapreduce.input.fileinputformat.split.minsize)mapred.min.split.size=10000000
       決定的 InputFormat的最小長度,默認為1,我們公司默認值是
    3.blockSize:HDFS 中的文件存儲塊block的大小,默認為128MB。
     
    這三個參數決定一個 InputFormat 分片的最終的長度,計算方法如下:
    splitSize = max{minSize,min{goalSize,blockSize}}

尖叫總結2:

     1.當hive處理的文件是非壓縮或者壓縮可切分,且hive.input.format為HiveInputFormat時,這個時候決定map個數的參數主要是splitSize = max{minSize,min{goalSize,blockSize}} ,只有這個時候一般map的splitsize小於等於blocksize(128Mb)。但其實這種方式現在企業實際開發中已經使用的很少了。
3.2.2.若hive.input.format為默認CombineHiveInputFormat

    1.如下,使用公司默認的map函數split參數,發現未壓縮的23.4g的文件(22個)這里共使用了112個map函數,符合參數的設置結果set mapred.max.split.size=256000000  ;  23.4*1024/112=187Mb<256000000。

    --使用默認配置參數,實現對非壓縮文件的操作
    set mapred.max.split.size=256000000  ;
    set mapred.min.split.size=10000000;
     
    drop table IF EXISTS fdm_tmp.company_liquidation_fgeics_company_ar_d_tmp;
    create table fdm_tmp.company_liquidation_fgeics_company_ar_d_tmp
    as
    select
     a.id
    ,a.entid
    ,a.ancheyear
    ,b.liqmen
    ,b.ligprincipal
    ,a.regno
    ,a.tel
    ,a.postalcode
    ,a.dom
    ,a.email
    ,a.busst
    ,a.empnum
    ,a.name
    ,a.updated
    ,b.etl_time
    from fdm_tmp.t_fgeics_company_liquidation_d_tmp  b
    right join fdm_tmp.company_liquidation_fgeics_company_ar_d  a
    on b.entid = a.entid;
     
    Hadoop job information for Stage-1: number of mappers: 112; number of reducers: 85
    Time taken: 152.679 seconds

   2.如下,將上面默認的參數對應調小,運行同樣上面的代碼,看map數是否有增加? 很顯然,我們通過設置max.split.size的值實現了增加map個數的功能。這里map的個數由122個數變成了199個,平均每個map處理數據120Mb左右。但是運行時間卻變慢了很多,時間由153s變成了243s。所以map的split大小並不是要接近blocksize才高效,這主要跟集群的性能配置有關。

    --將map的split參數最大值設置為128Mb.
    set mapred.max.split.size=134217728 ;
    set mapred.min.split.size=10000000;
     
    Hadoop job information for Stage-1: number of mappers: 199; number of reducers: 85
    Time taken: 243.038 seconds

  3.如下,將上面的默認參數增加,運行同樣的代碼,結果雖然我們將maxsplitsize設置的特別大,但是對應map的個數並沒有對應的成倍減少,如果按最大值算應該在20多個map,而實際不是這樣。這說明,光設置最大值是沒有用的,這只是一個峰值,還有對應的設置最小值。

    --只將max.split.size設置的特別大,min.split.size還是10Mb左右。
    set mapred.max.split.size=1024000000;
    set mapred.min.split.size= 10000000;
    Hadoop job information for Stage-1: number of mappers: 106; number of reducers: 85
     

4.map的多個參數配合使用,精確控制map的個數

     
    --1.只將max.split.size設置的特別大,且將 min.split.size使用默認值,發現map個數沒有成倍減少。
    set mapred.max.split.size=1024000000;
    set mapred.min.split.size=10000000;
    Hadoop job information for Stage-1: number of mappers: 106; number of reducers: 85
    ------------------------------------------------------------------------------------
    --2.同時將max.split.size設置的特別大,且將 min.split.size同時設置很大為256Mb左右
        但是發現map的個數並沒有減少,還是和上面一樣,這說明控制map的個數還有別的因素
    set mapred.max.split.size=1024000000;
    set mapred.min.split.size=256000000;
    Hadoop job information for Stage-1: number of mappers: 106; number of reducers: 85
    ------------------------------------------------------------------------------------
    ---3.配合min.split.size.per.node使用,發現map個數仍然沒有減少
     
    set mapred.max.split.size=1024000000;
    set mapred.min.split.size= 256000000;
    set mapred.min.split.size.per.node=256000000;--默認值是800000
    set mapred.min.split.size.per.rack=800000;---默認值
    --------------------------------------------------------------------------------------
    ---4.配合min.split.size.per.rack使用,map個數精准減少了,每個map處理的數據在256和1024之間
    Hadoop job information for Stage-1: number of mappers: 106; number of reducers: 85
    set mapred.max.split.size=1024000000;
    set mapred.min.split.size= 256000000;
    set mapred.min.split.size.per.node=256000000;
    set mapred.min.split.size.per.rack=256000000;
     
    Hadoop job information for Stage-1: number of mappers: 88; number of reducers: 85

尖叫總結3:

       如果Hive處理的的文件為非壓縮格式或者壓縮可切分,且inputFormat為CombineHiveInputFormat時,則控制map個數是由以下四個參數起作用,關於這四個參數作用優先級與使用注意事項請參考如下。

    mapred.min.split.size 或者 mapreduce.input.fileinputformat.split.minsize。
    mapred.max.split.size 或者 mapreduce.input.fileinputformat.split.maxsize。
    mapred.min.split.size.per.rack 或者 mapreduce.input.fileinputformat.split.minsize.per.rack。
    mapred.min.split.size.per.node 或者 mapreduce.input.fileinputformat.split.minsize.per.node。
     
    set hive.input.format = org.apache.hadoop.hive.ql.io.CombineHiveInputFormat; --hive0.5開始就是默認值,執行map前進行小文件合並
    ----------------------------------------------------------------------
    set mapred.max.split.size=256000000   --公司集群默認值
    set mapred.min.split.size=10000000     --公司集群默認值
    set mapred.min.split.size.per.node=8000000 --每個節點處理的最小split
    set mapred.min.split.size.per.rack=8000000 --每個機架處理的最小slit.
    ------------------------------------------------------------------------
    1.注意一般來說這四個參數的配置結果大小要滿足如下關系。
    max.split.size >= min.split.size >= min.size.per.node >= min.size.per.node
     
    2.這四個參數的作用優先級分別如下
    max.split.size <= min.split.size <= min.size.per.node <= min.size.per.node
     
    比如如下,同樣上面的代碼,我們將其參數設置如下,發現只啟動了12個map,故max.split.size沒有起作用。
    當四個參數設置矛盾時,系統會自動以優先級最高的參數為准,進行計算
    set mapred.max.split.size=300000000;
    set mapred.min.split.size.per.node=300000000;
    set mapred.min.split.size.per.rack=300000000;
    Hadoop job information for Stage-1: number of mappers: 12; number of reducers: 17
     
    3.注意這四個參數可以選擇性設置,可以選擇性設置大小或者使用默認值,但仍遵循前兩條規則。

       所以如果對於Hive調優,想通過控制map個數進行調優,首先確定集群是否啟動了壓縮,且壓縮的算法是否直接文件切分,然后再確定集群配置的默認的hive.input.format是什么實現類,不同實現類對於split的算法不同,當然控制map的參數也不同。所以對於控制map個數調優遠遠不是網上很多人說的那么簡單。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM