大多數開發人員都弄錯的Hive與MapReduce小文件合併問題

      近來我們公司搞小文件治理(小於10Mb),小文件太多的危害就不此贅述了。公司的開發人員提供的合併小文件治理配置如下:

-- 設置小文件合併
set hive.merge.mapfiles=true;
set hive.merge.mapredfiles=true;
set hive.merge.size.per.task = 256000000 ;
set hive.merge.smallfiles.avgsize= 256000000 ;

    看上去配置的沒啥問題,不管是Map-only,還是MapReduce都考慮到了,只要輸出的文件小於這個值,就重新啓動一個MR去執行文件合併。看也符合Hive官網的配置解釋

然而現實並非如此,廢話不多說,you can you code,no can no bb.

原分析表數據在HDFS存儲爲551個小文件,下面所有的測試都是基於這個文件。

1.測試代碼方案1

 設置啓動map前文件合併,先使用官方默認配置,實現文件合併測試

set  hive.input.format = org.apache.hadoop.hive.ql.io.CombineHiveInputFormat; --官方默認值,也是當前平臺默認值
set  hive.merge.smallfiles.avgsize=16000000;  --官方默認值,也是當前平臺默認值
set  hive.merge.size.per.task=256000000;  --官方默認值,也是當前平臺默認值
set  hive.merge.mapfiles  =true ;       --官方默認值,也是當前平臺默認值
set  hive.merge.mapredfiles = true ;  --官方默認值,也是當前平臺默認值

drop table if exists FDM_SOR.T_FSA_BHVR_NEW_EXPO_D_tmp_tmp;
create table FDM_SOR.t_fsa_bhvr_new_expo_d_tmp_tmp
stored as orc 
as 
select 
*  
from FDM_SOR.t_fsa_bhvr_new_expo_d 
where stat_date = '20200630'

結果:只產生了438個文件,看樣子效果不錯,文件變少了,但是發現還是有很多小於16Mb的文件,爲啥設置了不管用呢,是不是set hive.merge.smallfiles.avgsize官方的默認值給的太小了。需要加大。看實驗2.

 2.測試代碼方案2

設置啓動map前文件合併,將set hive.merge.smallfiles.avgsize值加大,增加文件合併的Size。按照官方的說法當輸出的文件平均小於16Mb時系統會再啓動一個MR進行文件合併。這下該管用了吧,請看:

set  hive.input.format = org.apache.hadoop.hive.ql.io.CombineHiveInputFormat; --官方默認值,也是當前平臺默認值
set  hive.merge.smallfiles.avgsize=256000000;  --改了這個值,由默認的16Mb,改成256Mb
set  hive.merge.size.per.task=256000000;  --官方默認值,也是當前平臺默認值
set  hive.merge.mapfiles  =true ;  --官方默認值,也是當前平臺默認值
set  hive.merge.mapredfiles = true ;  --官方默認值,也是當前平臺默認值

drop table if exists FDM_SOR.T_FSA_BHVR_NEW_EXPO_D_tmp_tmp;
create table FDM_SOR.t_fsa_bhvr_new_expo_d_tmp_tmp
stored as orc 
as 
select 
*  
from FDM_SOR.t_fsa_bhvr_new_expo_d 
where stat_date = '20200630'

廢話不多說,上結果請看

結果分析:沒錯,第一次MR因爲Combinetext啓動了438個map和上面一樣,果然接着又啓動了一個MR,進行輸出後的文件合併。看樣子很DIAO。合併要求文件大小不小256Mb,然後實際呢?pappa。文件雖然減少了很多到351個,但依然有很多小文件,很多小於10Mb的文件,這個時候心裏肯定一句

 

3.測試代碼方案3

    放大招,功夫有沒有,代碼走一走,加上split參數

set mapred.max.split.size=256000000;  
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;
set hive.merge.mapfiles = true ;
set hive.merge.mapredfiles = true ;
set hive.merge.size.per.task = 256000000 ;
set hive.merge.smallfiles.avgsize=160000000 ;

drop table if exists FDM_SOR.T_FSA_BHVR_NEW_EXPO_D_tmp_tmp;
create table FDM_SOR.T_FSA_BHVR_NEW_EXPO_D_tmp_tmp
stored as orc 
as 
select 
*  
from FDM_SOR.T_FSA_BHVR_NEW_EXPO_D 
where stat_date = '20200630'

廢話不多說,上結果請看:

結果分析:這下好了,全是大文件,44大文件,每個大文件都是辣麼大,最小的都是48Mb。爲啥加了split參數以後就生效了呢。前面單獨合併小文件參數沒啥效果呢?網上隨便搜一下,都是這種配置這種參數的?

-- 設置小文件合併
set hive.merge.mapfiles=true;
set hive.merge.mapredfiles=true;
set hive.merge.size.per.task = 256000000 ;
set hive.merge.smallfiles.avgsize= 256000000 ;

4.答案揭曉

         因爲設置上面四個參數,看上去規定了map結束,MR結束合併文件,如果文件平均小於smallfiles.avgsize啓動一個新的MRj進行文件的二次合併。如果啓動mr合併文件,沒有問題。但是忽略了一個問題,你重新啓動一個mr合併文件,這個mr是不是需要進行文件split,你這個參數搞小了,那就會產生很多task,很多map,比如很多小文件就是一個map,最終還是產生很多小文件(因爲合併小文件的mr只有map)。所以必須要配合split參數纔有用。具體split參數使用,參考我其他博客。

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