Hive 插入動態分區表時遇到的一些坑

Hive 插入動態分區的問題

insert into table xxx partition(xxxx)
select ...

使用動態分區時首先不要忘記的一些配置:

  • 是否開啓動態分區 hive.exec.dynamic.partition
  • 動態分區是否使用嚴格模式 hive.exec.dynamic.partition.mode
  • MR總共可創建最大分區數 hive.exec.max.dynamic.partition.partitions (默認1000)以及當前節點可創建的最大分區數 hive.exec.max.dynamic.partition.partitions.pernode (默認100)

動態分區產生大量小文件

我這裏分區表的存儲格式是Parquet,insert select方式動態插入動態分區中,按天分區數據量非常大,一天幾十G的文件
因爲數據量大,而且分區數多,就會起大量map,從而產生大量小文件(map數x分區數)。小文件過多不僅影響查詢,NameNode中的元數據信息管理也會受很大影響

insert into table xxx partition(pcol)
select ...
from ...
distribute by(pcol)

這樣做分區數決定了reduce數,reduce數也決定了文件數,雖然可以減少文件數,但會導致數據傾斜的產生

insert into table xxx partition(pcol)
select ...
from ...
distribute by rand()

通過rand()結果hash編碼後對reducer數取餘,可以把數據均分到reducer上去。數據量很大的話能保證每個reduce上都有和pcol分區數相等的文件數。所以文件數可以由reducer個數限制,hive.exec.reducers.max

順便提一句,distribute by rand()也可以用來隨機抽樣,因爲隨機分發到reducers上去了,也就等同於隨機抽取了

我嘗試這樣做了後,又出現了OOM錯誤,google了一番找到了下面這個配置參數

  • hive.optimize.sort.dynamic.partition

官網解釋是:When enabled, dynamic partitioning column will be globally sorted. This way we can keep only one record writer open for each partition value in the reducer thereby reducing the memory pressure on reducers.

Hive 0.13加入並默認true,Hive 0.14後默認爲false,如果爲true的話,這個參數可以使得每個分區只產生一個文件,可以解決動態分區時的OOM問題,但會嚴重降低reduce處理並寫入一個分區的速度
這裏設置爲true後成功了。但這個參數的後果就是慢,這篇文章有談及要綜合業務考慮是否開啓:https://hdinsight.github.io/hive/hive-slow-reducer.html

動態分區插入時OOM問題的產生

還是上面hive.optimize.sort.dynamic.partition這個參數。產生OOM問題的原因是同時打開了太多寫分區的record writer同時寫入文件,開啓該參數的話,分區列會全局排序,使得reduce端每個分區只有一個文件寫入,降低reduce的內存壓力

具體OOM的原因我在這裏看到了:https://cloud.tencent.com/developer/article/1079007

Parquet和ORC是列式批處理文件格式。這些格式要求在寫入文件之前將批次的行(batches of rows)緩存在內存中。在執行INSERT語句時,動態分區目前的實現是:至少爲每個動態分區目錄打開一個文件寫入器(file writer)。由於這些緩衝區是按分區維護的,因此在運行時所需的內存量隨着分區數量的增加而增加。所以經常會導致mappers或reducers的OOM,具體取決於打開的文件寫入器(file writer)的數量

https://community.hortonworks.com/content/supportkb/171090/hive-query-with-dynamic-partition-takes-long-time.html
https://community.hortonworks.com/articles/89522/hive-insert-to-dynamic-partition-query-generating.html
要是還報OOM問題,進一步可以考慮調整map、reduce的內存大 mapreduce.map.memory.mbmapreduce.reduce.memory.mb 參數

Hive 控制文件數過多的一些參數

這個是搜索上面遇到的問題時遇見的,覺得有價值,也談及了上面提到的distribute by,所以再次記錄下

參考:https://www.jianshu.com/p/e76ddc4b19c5

說的是hive.exec.max.created.files 參數,默認是10000,超過這個數會報錯exceeds 100000.Killing the job

設置 mapper輸入文件合併的參數

set mapred.max.split.size=256000000;  #每個Map最大輸入大小
set mapred.min.split.size.per.node=100000000; #一個節點上split的至少的大小(這個值決定了多個DataNode上的文件是否需要合併)
set mapred.min.split.size.per.rack=100000000; #一個交換機下split的至少的大小(這個值決定了該機架下的文件是否需要合併)
set hive.input.format=org.apache.Hadoop.hive.ql.io.CombineHiveInputFormat;  # 執行Map前進行小文件合併

在開啓了org.apache.hadoop.hive.ql.io.CombineHiveInputFormat後,一個data node節點上多個小文件會進行合併,合併文件數由mapred.max.split.size限制的大小決定。
mapred.min.split.size.per.node決定了多個DataNode上的文件是否需要合併
mapred.min.split.size.per.rack決定了多個交換機上的文件是否需要合併

設置 map輸出和reduce輸出進行合併的參數

hive.merge.mapfiles= true    #設置 map輸出和reduce輸出進行合併的相關參數
hive.merge.mapredfiles= true 設置reduce端輸出進行合併,默認爲false
hive.merge.size.per.task= 256 *1000 * 1000  設置合併文件的大小
hive.merge.smallfiles.avgsize=16000000   輸出文件的平均大小小於該值時,啓動一個獨立的MapReduce任務進行文件merge

順便記錄下其他或許會用到的Hive調優參數:

更多大數據相關Tips可以關注:https://github.com/josonle/Coding-Nowhttps://github.com/josonle/BigData-Learning

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