數(shù)倉(cāng)面試高頻考點(diǎn)--解決hive小文件過(guò)多問(wèn)題
點(diǎn)擊上方 "大數(shù)據(jù)肌肉猿"關(guān)注,?星標(biāo)一起成長(zhǎng)
后臺(tái)回復(fù)【加群】,進(jìn)入高質(zhì)量學(xué)習(xí)交流群
2021年大數(shù)據(jù)肌肉猿公眾號(hào)獎(jiǎng)勵(lì)制度

小文件產(chǎn)生原因
hive 中的小文件肯定是向 hive 表中導(dǎo)入數(shù)據(jù)時(shí)產(chǎn)生,所以先看下向 hive 中導(dǎo)入數(shù)據(jù)的幾種方式
直接向表中插入數(shù)據(jù)
insert?into?table?A?values?(1,'zhangsan',88),(2,'lisi',61);
這種方式每次插入時(shí)都會(huì)產(chǎn)生一個(gè)文件,多次插入少量數(shù)據(jù)就會(huì)出現(xiàn)多個(gè)小文件,但是這種方式生產(chǎn)環(huán)境很少使用,可以說(shuō)基本沒(méi)有使用的
通過(guò)load方式加載數(shù)據(jù)
load?data?local?inpath?'/export/score.csv'?overwrite?into?table?A??--?導(dǎo)入文件
load?data?local?inpath?'/export/score'?overwrite?into?table?A???--?導(dǎo)入文件夾
使用 load 方式可以導(dǎo)入文件或文件夾,當(dāng)導(dǎo)入一個(gè)文件時(shí),hive表就有一個(gè)文件,當(dāng)導(dǎo)入文件夾時(shí),hive表的文件數(shù)量為文件夾下所有文件的數(shù)量
通過(guò)查詢(xún)方式加載數(shù)據(jù)
insert?overwrite?table?A??select?s_id,c_name,s_score?from?B;
這種方式是生產(chǎn)環(huán)境中常用的,也是最容易產(chǎn)生小文件的方式
insert 導(dǎo)入數(shù)據(jù)時(shí)會(huì)啟動(dòng) MR 任務(wù),MR中 reduce 有多少個(gè)就輸出多少個(gè)文件
所以, 文件數(shù)量=ReduceTask數(shù)量*分區(qū)數(shù)
也有很多簡(jiǎn)單任務(wù)沒(méi)有reduce,只有map階段,則
文件數(shù)量=MapTask數(shù)量*分區(qū)數(shù)
每執(zhí)行一次 insert 時(shí)hive中至少產(chǎn)生一個(gè)文件,因?yàn)?insert 導(dǎo)入時(shí)至少會(huì)有一個(gè)MapTask。
像有的業(yè)務(wù)需要每10分鐘就要把數(shù)據(jù)同步到 hive 中,這樣產(chǎn)生的文件就會(huì)很多。
小文件過(guò)多產(chǎn)生的影響
首先對(duì)底層存儲(chǔ)HDFS來(lái)說(shuō),HDFS本身就不適合存儲(chǔ)大量小文件,小文件過(guò)多會(huì)導(dǎo)致namenode元數(shù)據(jù)特別大, 占用太多內(nèi)存,嚴(yán)重影響HDFS的性能
對(duì) hive 來(lái)說(shuō),在進(jìn)行查詢(xún)時(shí),每個(gè)小文件都會(huì)當(dāng)成一個(gè)塊,啟動(dòng)一個(gè)Map任務(wù)來(lái)完成,而一個(gè)Map任務(wù)啟動(dòng)和初始化的時(shí)間遠(yuǎn)遠(yuǎn)大于邏輯處理的時(shí)間,就會(huì)造成很大的資源浪費(fèi)。而且,同時(shí)可執(zhí)行的Map數(shù)量是受限的。
怎么解決小文件過(guò)多
1. 使用 hive 自帶的 concatenate 命令,自動(dòng)合并小文件
使用方法:
#對(duì)于非分區(qū)表
alter?table?A?concatenate;
#對(duì)于分區(qū)表
alter?table?B?partition(day=20201224)?concatenate;
舉例:
#向?A?表中插入數(shù)據(jù)
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);
#執(zhí)行以上三條語(yǔ)句,則A表下就會(huì)有三個(gè)小文件,在hive命令行執(zhí)行如下語(yǔ)句
#查看A表下文件數(shù)量
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
#可以看到有三個(gè)小文件,然后使用?concatenate?進(jìn)行合并
hive?(default)>?alter?table?A?concatenate;
#再次查看A表下文件數(shù)量
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
#已合并成一個(gè)文件
注意:?
1、concatenate 命令只支持 RCFILE 和 ORC 文件類(lèi)型。?
2、使用concatenate命令合并小文件時(shí)不能指定合并后的文件數(shù)量,但可以多次執(zhí)行該命令。?
3、當(dāng)多次使用concatenate后文件數(shù)量不在變化,這個(gè)跟參數(shù) mapreduce.input.fileinputformat.split.minsize=256mb 的設(shè)置有關(guān),可設(shè)定每個(gè)文件的最小size。
2. 調(diào)整參數(shù)減少M(fèi)ap數(shù)量
設(shè)置map輸入合并小文件的相關(guān)參數(shù):
#執(zhí)行Map前進(jìn)行小文件合并
#CombineHiveInputFormat底層是?Hadoop的?CombineFileInputFormat?方法
#此方法是在mapper中將多個(gè)文件合成一個(gè)split作為輸入
set?hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;?--?默認(rèn)
#每個(gè)Map最大輸入大小(這個(gè)值決定了合并后文件的數(shù)量)
set?mapred.max.split.size=256000000;???--?256M
#一個(gè)節(jié)點(diǎn)上split的至少的大小(這個(gè)值決定了多個(gè)DataNode上的文件是否需要合并)
set?mapred.min.split.size.per.node=100000000;??--?100M
#一個(gè)交換機(jī)下split的至少的大小(這個(gè)值決定了多個(gè)交換機(jī)上的文件是否需要合并)
set?mapred.min.split.size.per.rack=100000000;??--?100M
設(shè)置map輸出和reduce輸出進(jìn)行合并的相關(guān)參數(shù):
#設(shè)置map端輸出進(jìn)行合并,默認(rèn)為true
set?hive.merge.mapfiles?=?true;
#設(shè)置reduce端輸出進(jìn)行合并,默認(rèn)為false
set?hive.merge.mapredfiles?=?true;
#設(shè)置合并文件的大小
set?hive.merge.size.per.task?=?256*1000*1000;???--?256M
#當(dāng)輸出文件的平均大小小于該值時(shí),啟動(dòng)一個(gè)獨(dú)立的MapReduce任務(wù)進(jìn)行文件merge
set?hive.merge.smallfiles.avgsize=16000000;???--?16M?
啟用壓縮
#?hive的查詢(xún)結(jié)果輸出是否進(jìn)行壓縮
set?hive.exec.compress.output=true;
#?MapReduce?Job的結(jié)果輸出是否使用壓縮
set?mapreduce.output.fileoutputformat.compress=true;
3. 減少Reduce的數(shù)量
#reduce?的個(gè)數(shù)決定了輸出的文件的個(gè)數(shù),所以可以調(diào)整reduce的個(gè)數(shù)控制hive表的文件數(shù)量,
#hive中的分區(qū)函數(shù)?distribute?by?正好是控制MR中partition分區(qū)的,
#然后通過(guò)設(shè)置reduce的數(shù)量,結(jié)合分區(qū)函數(shù)讓數(shù)據(jù)均衡的進(jìn)入每個(gè)reduce即可。
#設(shè)置reduce的數(shù)量有兩種方式,第一種是直接設(shè)置reduce個(gè)數(shù)
set?mapreduce.job.reduces=10;
#第二種是設(shè)置每個(gè)reduce的大小,Hive會(huì)根據(jù)數(shù)據(jù)總大小猜測(cè)確定一個(gè)reduce個(gè)數(shù)
set?hive.exec.reducers.bytes.per.reducer=5120000000;?--?默認(rèn)是1G,設(shè)置為5G
#執(zhí)行以下語(yǔ)句,將數(shù)據(jù)均衡的分配到reduce中
set?mapreduce.job.reduces=10;
insert?overwrite?table?A?partition(dt)
select?*?from?B
distribute?by?rand();
解釋?zhuān)喝缭O(shè)置reduce數(shù)量為10,則使用 rand(),?隨機(jī)生成一個(gè)數(shù) x % 10?,
這樣數(shù)據(jù)就會(huì)隨機(jī)進(jìn)入?reduce?中,防止出現(xiàn)有的文件過(guò)大或過(guò)小
4. 使用hadoop的archive將小文件歸檔
Hadoop Archive簡(jiǎn)稱(chēng)HAR,是一個(gè)高效地將小文件放入HDFS塊中的文件存檔工具,它能夠?qū)⒍鄠€(gè)小文件打包成一個(gè)HAR文件,這樣在減少namenode內(nèi)存使用的同時(shí),仍然允許對(duì)文件進(jìn)行透明的訪(fǎng)問(wèn)
#用來(lái)控制歸檔是否可用
set?hive.archive.enabled=true;
#通知Hive在創(chuàng)建歸檔時(shí)是否可以設(shè)置父目錄
set?hive.archive.har.parentdir.settable=true;
#控制需要?dú)w檔文件的大小
set?har.partfile.size=1099511627776;
#使用以下命令進(jìn)行歸檔
ALTER?TABLE?A?ARCHIVE?PARTITION(dt='2020-12-24',?hr='12');
#對(duì)已歸檔的分區(qū)恢復(fù)為原文件
ALTER?TABLE?A?UNARCHIVE?PARTITION(dt='2020-12-24',?hr='12');
注意: ?
歸檔的分區(qū)可以查看不能 insert overwrite,必須先 unarchive
最后
如果是新集群,沒(méi)有歷史遺留問(wèn)題的話(huà),建議hive使用 orc 文件格式,以及啟用 lzo 壓縮。
這樣小文件過(guò)多可以使用hive自帶命令 concatenate 快速合并。
原創(chuàng)專(zhuān)輯:
技術(shù)漫畫(huà)與職場(chǎng)經(jīng)驗(yàn)
·················END·················
你好,我是峰哥,一個(gè)騷氣的肌肉男。獨(dú)自窮游過(guò)15個(gè)國(guó)家,60座城市,也是國(guó)家級(jí)健身教練。
二本車(chē)輛工程轉(zhuǎn)型大數(shù)據(jù)開(kāi)發(fā),拿過(guò)66個(gè)大數(shù)據(jù)offer,現(xiàn)任某知名外企高級(jí)數(shù)據(jù)工程師。
畢業(yè)一年,靠自己在上海買(mǎi)房,點(diǎn)此看我2020年總結(jié)。為人親和,歡迎添加我的微信?Fawn0504?進(jìn)行交流或圍觀朋友圈。
