1. 程式人生 > >數倉面試高頻考點--解決hive小檔案過多問題

數倉面試高頻考點--解決hive小檔案過多問題

**本文首發於公眾號:五分鐘學大資料** ### 小檔案產生原因 hive 中的小檔案肯定是向 hive 表中匯入資料時產生,所以先看下向 hive 中匯入資料的幾種方式 1. 直接向表中插入資料 ``` insert into table A values (1,'zhangsan',88),(2,'lisi',61); ``` 這種方式每次插入時都會產生一個檔案,多次插入少量資料就會出現多個小檔案,但是這種方式生產環境很少使用,可以說基本沒有使用的 2. 通過load方式載入資料 ``` load data local inpath '/export/score.csv' overwrite into table A -- 匯入檔案 load data local inpath '/export/score' overwrite into table A -- 匯入資料夾 ``` 使用 load 方式可以匯入檔案或資料夾,當匯入一個檔案時,hive表就有一個檔案,當匯入資料夾時,hive表的檔案數量為資料夾下所有檔案的數量 3. 通過查詢方式載入資料 ``` insert overwrite table A select s_id,c_name,s_score from B; ``` 這種方式是生產環境中常用的,也是最容易產生小檔案的方式 insert 匯入資料時會啟動 MR 任務,MR中 reduce 有多少個就輸出多少個檔案 所以, 檔案數量=ReduceTask數量\*分割槽數 也有很多簡單任務沒有reduce,只有map階段,則 檔案數量=MapTask數量\*分割槽數 每執行一次 insert 時hive中至少產生一個檔案,因為 insert 匯入時至少會有一個MapTask。 像有的業務需要每10分鐘就要把資料同步到 hive 中,這樣產生的檔案就會很多。 ### 小檔案過多產生的影響 1. 首先對底層儲存HDFS來說,HDFS本身就不適合儲存大量小檔案,小檔案過多會導致namenode元資料特別大, 佔用太多記憶體,嚴重影響HDFS的效能 2. 對 hive 來說,在進行查詢時,每個小檔案都會當成一個塊,啟動一個Map任務來完成,而一個Map任務啟動和初始化的時間遠遠大於邏輯處理的時間,就會造成很大的資源浪費。而且,同時可執行的Map數量是受限的。 ### 怎麼解決小檔案過多 #### 1. 使用 hive 自帶的 concatenate 命令,自動合併小檔案 使用方法: ``` #對於非分割槽表 alter table A concatenate; #對於分割槽表 alter table B partition(day=20201224) concatenate; ``` 舉例: ```sql #向 A 表中插入資料 hive (default)> insert into table A values (1,'aa',67),(2,'bb',87); hive (default)> insert into table A values (3,'cc',67),(4,'dd',87); hive (default)> insert into table A values (5,'ee',67),(6,'ff',87); #執行以上三條語句,則A表下就會有三個小檔案,在hive命令列執行如下語句 #檢視A表下檔案數量 hive (default)> dfs -ls /user/hive/warehouse/A; Found 3 items -rwxr-xr-x 3 root supergroup 378 2020-12-24 14:46 /user/hive/warehouse/A/000000_0 -rwxr-xr-x 3 root supergroup 378 2020-12-24 14:47 /user/hive/warehouse/A/000000_0_copy_1 -rwxr-xr-x 3 root supergroup 378 2020-12-24 14:48 /user/hive/warehouse/A/000000_0_copy_2 #可以看到有三個小檔案,然後使用 concatenate 進行合併 hive (default)> alter table A concatenate; #再次檢視A表下檔案數量 hive (default)> dfs -ls /user/hive/warehouse/A; Found 1 items -rwxr-xr-x 3 root supergroup 778 2020-12-24 14:59 /user/hive/warehouse/A/000000_0 #已合併成一個檔案 ``` > 注意: 1、concatenate 命令只支援 RCFILE 和 ORC 檔案型別。 2、使用concatenate命令合併小檔案時不能指定合併後的檔案數量,但可以多次執行該命令。 3、當多次使用concatenate後文件數量不在變化,這個跟引數 mapreduce.input.fileinputformat.split.minsize=256mb 的設定有關,可設定每個檔案的最小size。 #### 2. 調整引數減少Map數量 - **設定map輸入合併小檔案的相關引數**: ``` #執行Map前進行小檔案合併 #CombineHiveInputFormat底層是 Hadoop的 CombineFileInputFormat 方法 #此方法是在mapper中將多個檔案合成一個split作為輸入 set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat; -- 預設 #每個Map最大輸入大小(這個值決定了合併後文件的數量) set mapred.max.split.size=256000000; -- 256M #一個節點上split的至少的大小(這個值決定了多個DataNode上的檔案是否需要合併) set mapred.min.split.size.per.node=100000000; -- 100M #一個交換機下split的至少的大小(這個值決定了多個交換機上的檔案是否需要合併) set mapred.min.split.size.per.rack=100000000; -- 100M ``` - **設定map輸出和reduce輸出進行合併的相關引數**: ``` #設定map端輸出進行合併,預設為true set hive.merge.mapfiles = true; #設定reduce端輸出進行合併,預設為false set hive.merge.mapredfiles = true; #設定合併檔案的大小 set hive.merge.size.per.task = 256*1000*1000; -- 256M #當輸出檔案的平均大小小於該值時,啟動一個獨立的MapReduce任務進行檔案merge set hive.merge.smallfiles.avgsize=16000000; -- 16M ``` - **啟用壓縮** ``` # hive的查詢結果輸出是否進行壓縮 set hive.exec.compress.output=true; # MapReduce Job的結果輸出是否使用壓縮 set mapreduce.output.fileoutputformat.compress=true; ``` #### 3. 減少Reduce的數量 ``` #reduce 的個數決定了輸出的檔案的個數,所以可以調整reduce的個數控制hive表的檔案數量, #hive中的分割槽函式 distribute by 正好是控制MR中partition分割槽的, #然後通過設定reduce的數量,結合分割槽函式讓資料均衡的進入每個reduce即可。 #設定reduce的數量有兩種方式,第一種是直接設定reduce個數 set mapreduce.job.reduces=10; #第二種是設定每個reduce的大小,Hive會根據資料總大小猜測確定一個reduce個數 set hive.exec.reducers.bytes.per.reducer=5120000000; -- 預設是1G,設定為5G #執行以下語句,將資料均衡的分配到reduce中 set mapreduce.job.reduces=10; insert overwrite table A partition(dt) select * from B distribute by rand(); 解釋:如設定reduce數量為10,則使用 rand(), 隨機生成一個數 x % 10 , 這樣資料就會隨機進入 reduce 中,防止出現有的檔案過大或過小 ``` #### 4. 使用hadoop的archive將小檔案歸檔 Hadoop Archive簡稱HAR,是一個高效地將小檔案放入HDFS塊中的檔案存檔工具,它能夠將多個小檔案打包成一個HAR檔案,這樣在減少namenode記憶體使用的同時,仍然允許對檔案進行透明的訪問 ``` #用來控制歸檔是否可用 set hive.archive.enabled=true; #通知Hive在建立歸檔時是否可以設定父目錄 set hive.archive.har.parentdir.settable=true; #控制需要歸檔檔案的大小 set har.partfile.size=1099511627776; #使用以下命令進行歸檔 ALTER TABLE A ARCHIVE PARTITION(dt='2020-12-24', hr='12'); #對已歸檔的分割槽恢復為原檔案 ALTER TABLE A UNARCHIVE PARTITION(dt='2020-12-24', hr='12'); ``` > 注意: **歸檔的分割槽可以檢視不能 insert overwrite,必須先 unarchive** #### 最後 如果是新叢集,沒有歷史遺留問題的話,建議hive使用 orc 檔案格式,以及啟用 lzo 壓縮。 這樣小檔案過多可以使用hive自帶命令 concatenate 快速合併。 如果你想獲取更多大資料相關技術文章,可關注公眾號:**五分鐘學大資料**,專注於大資料技術研究,分享高質量的原創技