HIVE SQL產生的文件數量及參數調優


  產生背景:sqoop抽取oracle數據到hive表時,只能寫入到固定分區(--hive-partition-key #hive分區字段 --hive-partition-value #hive分區值)。於是先把數據抽取到一張增量表,然后從增量表動態寫入分區表。

set hive.exec.dynamic.partition.mode = true;  --使用動態分區時,設置為ture。
set hive.exec.dynamic.partition.mode = nonstrict;  --動態分區模式,默認值:strict,表示必須指定一個分區為靜態分區;nonstrict模式表示允許所有的分區字段都可以使用動態分區。一般需要設置為nonstrict。
set hive.exec.max.dynamic.partitions.pernode =10;  --在每個執行MR的節點上,最多可以創建多少個動態分區,默認值:100。
set hive.exec.max.dynamic.partitions =1000;  --在所有執行MR的節點上,最多一共可以創建多少個動態分區,默認值:1000。
set hive.exec.max.created.files = 100000;  --整個MR Job中最多可以創建多少個HDFS文件,默認值:100000。
set hive.error.on.empty.partition = false;  --當有空分區產生時,是否拋出異常,默認值:false。

 

  Hive文件產生大量小文件的原因:

    一是文件本身的原因:小文件多,以及文件的大小;

    二是使用動態分區,可能會導致產生大量分區,從而產生很多小文件,也會導致產生很多Mapper;

    三是Reduce數量較多,Hive SQL輸出文件的數量和Reduce的個數是一樣的。

  小文件帶來的影響:

    文件的數量和大小決定Mapper任務的數量,小文件越多,Mapper任務越多,每一個Mapper都會啟動一個JVM來運行,所以這些任務的初始化和執行會花費大量的資源,嚴重影響性能。

    在NameNode中每個文件大約占150字節,小文件多,會嚴重影響NameNode性能。

  解決小文件問題:

    如果動態分區數量不可預測,最好不用。如果用,最好使用distributed by分區字段,這樣會對字段進行一個hash操作,把相同的分區給同一個Reduce處理;

    減少Reduce數量;

    進行以一些參數調整。

控制Mapper的數量:

  決定Mapper的數量的因素有:輸入文件的個數,輸入文件的大小、集群設置的文件塊大小。

    例如:輸入目錄下有1個800M的文件,hadoop會將文件分成7個文件(6*128M + 1*32M),從而產生7個Mapper數;

    例如:輸入目錄下有5個文件,分別為:15M、20M、50M、100M、150M,那么hadoop會分隔成6個文件(15M、20M、50M、100M、128M、22M),從而產生6個Mapper。

  可以通過設置如下參數,讓Map在執行之前合並小文件,從而減少Mapper數量:

set mapred.max.split.size=100000000;   -- 決定每個map處理的最大的文件大小,單位為B
set mapred.min.split.size.per.node=100000000;   -- 節點中可以處理的最小的文件大小
set mapred.min.split.size.per.rack=100000000;   -- 機架中可以處理的最小的文件大小
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;  ---實現map中的數據合並需要設置下面的參數,集群默認就是這個格式

  

  控制Mapper的整體原則:

    大數據量要利用合適的map數,單個map要處理合適的數據量;

    map占用資源要合並小文件,map不足要把大文件拆成小文件。

控制Reduce的數量:

  Reduce的個數會極大影響任務的執行效率

  • Hive自己確定reduce數

    不指定Reduce的個數的情況下,Hive會猜測確定一個Reduce個數,由下面兩個參數決定:

    1、hive.exec.reducers.bytes.per.reducer(每個reduce任務處理的數據量,默認為1000^3=1G) 

    2、hive.exec.reducers.max(每個任務最大的reduce數,默認為999)

    Reduce的個數N=min(參數2,輸入總數據量/參數1),例如:如果Reduce的輸入(map的輸出)總大小不超過1G,那么只有一個Reduce任務。

  • 手動調整reduce數

    Hive官網:

In order to change the average load for a reducer (in bytes): set hive.exec.reducers.bytes.per.reducer=<number>
In order to limit the maximum number of reducers: set hive.exec.reducers.max=<number>
In order to set a constant number of reducers: set mapreduce.job.reduces=<number>

  Notes:動態分區采坑

    在使用動態分區的時候,如果已知數據會分成n個分區,SQL運行的時候創建了m個Mapper,則這個SQL產生m * n個文件。如果這個數值大於設置的創建文件的總數(hive.exec.max.created.files),默認值100000個,就會出現異常。

    在未知動態分區數時,可以使用distribute by 分區字段,將分區字段內容相同的數據放到同一個reduce,當然也可以使用distribute by rand()將數據隨記分配給reduce,這樣可以使每個reduce處理的數據大體相同。

  • 和map一樣,啟動和初始化reduce會消耗時間和資源,有多少reduce就會產生多少個文件
  • 以下情況下,會只有一個reduce:
    • 沒有group by的匯總,如把select dt,count(1) from test where dt = '2019-12-12' group by dt;,寫成select count(1) from test where dt = '2019-12-12';
    • 用了order by;
    • 有笛卡爾積;

  控制Reduce的整體原則:

    使大數據量利用合適的reduce數;

    使單個reduce任務處理合適的數據量。

  


免責聲明!

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



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