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.mb
和 mapreduce.reduce.memory.mb
參數
Hive 控制文件數過多的一些參數
這個是搜索上面遇到的問題時遇見的,覺得有價值,也談及了上面提到的distribute by,所以再次記錄下
說的是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調優參數:
- https://blog.csdn.net/high2011/article/details/78999420
- https://blog.csdn.net/renzhixin1314/article/details/70496325
更多大數據相關Tips可以關注:https://github.com/josonle/Coding-Now 和 https://github.com/josonle/BigData-Learning