徹底解決Hive小文件問題
最近發現離線任務對一個增量Hive
表的查詢越來越慢,這引起了我的注意,我在cmd
窗口手動執行count
操作查詢發現,速度確實很慢,才不到五千萬的數據,居然需要300s
,這顯然是有問題的,我推測可能是有小文件。
我去hdfs
目錄查看了一下該目錄:
發現確實有很多小文件,有480個小文件,我覺得我找到了問題所在,那麼合併一下小文件吧:
insert into test select * from table distribute by floor (rand()*5);
這裡使用distribute by
進行了一個小文件的合併,通過rand() * 5
,保證了從map端輸出的數據,最多到5個reducer
,將小文件數量控制了下來,現在只有3個文件了。
合併小文件後,再次做同樣的查詢,15s
就完成了。確實忽略了,增量數據會導致小文件,應該在當初做的時候就做定時的小文件合併,而不是等到現在才發現。
因為這個表每天是有增量數據進去的,增量數據會單獨生成一個文件,因為增量數據本身不大,日積月累就形成了大量小文件。不僅對namenode
的記憶體造成壓力,對map端的小文件合併也有很大壓力。
小文件產生的原因
-
動態分區插入數據的時候,會產生大量的小文件;
-
數據源本身就包含有大量的小文件;
-
做增量導入,比如Sqoop數據導入,一些增量insert等;
-
分桶表,分桶表通常也會遇到小文件,本質上還是增量導入的問題;
-
可以修改的表,這種Hive表是可以進行修改的,通過配置
stored as orc TBLPROPERTIES ("transactional"="true")
,這種表最坑,每天都會有一個快照,到後面10G大小的數據,表文件體積可以達到600G,時間越長越大;
小文件的問題有很多,實際中各種原因,由於自己的不小心,前期沒有做好預防都會產生大量小文件,讓線上的離線任務神不知鬼不覺,越跑越慢。
小文件的危害
- 給namenode記憶體中fsImage的合併造成壓力,如果namenode記憶體使用完了,這個集群將不能再存儲文件了;
- 雖然map階段都設置了小文件合併,
org.apache.hadoop.hive.ql.io.CombineHiveInputFormat
,太多小文件導致合併時間較長,查詢緩慢;
小文件的解決方案
徹底解決小文件,分為了兩個方向,一個是小文件的預防,一個是大量小文件問題已經出現了,我們該怎麼解決。
1. 小文件的預防
網上有些解決方案,是調節參數,這些參數在我使用的Hive2
是默認都開啟了的:
//每個Map最大輸入大小(這個值決定了合併後文件的數量)
set mapred.max.split.size=256000000;
//一個節點上split的至少的大小(這個值決定了多個DataNode上的文件是否需要合併)
set mapred.min.split.size.per.node=100000000;
//一個交換機下split的至少的大小(這個值決定了多個交換機上的文件是否需要合併)
set mapred.min.split.size.per.rack=100000000;
//執行Map前進行小文件合併
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
//設置map端輸出進行合併,默認為true
set hive.merge.mapfiles = true
//設置reduce端輸出進行合併,默認為false
set hive.merge.mapredfiles = true
//設置合併文件的大小
set hive.merge.size.per.task = 256*1000*1000
//當輸出文件的平均大小小於該值時,啟動一個獨立的MapReduce任務進行文件merge。
set hive.merge.smallfiles.avgsize=16000000
有些公司用的版本不同,低版本可能有些配置不一樣,最好檢查一下上面這些配置是否設置,然後根據自己的實際集群情況進行設置。
小文件的預防,主要還是要根據小文件的產生原因,來進行預防。
- 動態分區插入的時候,保證有靜態分區,不要誤判導致產生大量分區,大量分區加起來,自然就有大量小文件;
- 如果源表是有大量小文件的,在導入數據到目標表的時候,如果只是
insert into dis select * from origin
的話,目標表通常也有很多小文件。如果有分區,比如dt, hour
,可以使用distribute by dt, hour
,保證每個小時的數據在一個reduce裡面; - 類似
sqoop
增量導入,還有hive
一些表的查詢增量導入,這些肯定是有小文件的,需要進行一周甚至一天定時任務的小文件合併。
2. 小文件的解決
上面是平時開發數據任務時候,小文件的預防,但如果由於我們的大意,小文件問題已經產生了,就需要解決了。通常就是insert overwrite
了。
insert overwrite table test [partition(hour=...)] select * from test distribute by floor (rand()*5);
註:這個語句把test
表的數據查詢出來,overwrite
覆蓋test
表,不用擔心如果overwrite
失敗,數據沒了,這裡面是有事物性保證的,可以觀察一下執行的時候,在test表hdfs
文件目錄下面有個臨時文件夾。如果是分區表,加上partition
,表示對該分區進行overwrite
。
如果是orc格式存儲的表,還可以使用alter table test [partition(...)] concatenate
進行小文件的合併,不過這種方法僅僅適用於orc格式存儲的表。
猜你喜歡
Hadoop3數據容錯技術(糾刪碼)
Hadoop 數據遷移用法詳解
Flink實時計算topN熱榜
數倉建模分層理論
一文搞懂Hive的數據存儲與壓縮
大數據組件重點學習這幾個