磁盤:
heads/sectors/cylinders,分別就是磁頭/扇區/柱面,每個扇區512byte(現在新的硬盤每個扇區有4K)
文件系統:
文件系統不是一個扇區一個扇區的來讀數據,太慢了,所以有了block(塊)的概念,它是一個塊一個塊的讀取的,block才是文件存取的最小單位。
文件系統中1個塊是由連續的8個扇區組成。
HDFS:
默認文件大小64M(或者是128M)
hive小文件問題解決
問題描述
HDFS的文件元信息,包括位置、大小、分塊信息等,都是保存在NameNode的內存中的。每個對象大約占用150個字節,因此一千萬個文件及分塊就會占用約3G的內存空間,一旦接近這個量級,NameNode的性能就會開始下降了。
Hive小文件產生的原因
前面已經提到,匯總后的數據量通常比源數據要少得多。而為了提升運算速度,我們會增加Reducer的數量,Hive本身也會做類似優化——Reducer數量等於源數據的量除以hive.exec.reducers.bytes.per.reducer所配置的量(默認1G)。Reducer數量的增加也即意味着結果文件的增加,從而產生小文件的問題。
解決小文件的問題可以從兩個方向入手:
1. 輸入合並。即在Map前合並小文件
2. 輸出合並。即在輸出結果的時候合並小文件
配置Map輸入合並
set hive.merge.mapfiles = true ##在 map only 的任務結束時合並小文件
set hive.merge.mapredfiles = false ## true 時在 MapReduce 的任務結束時合並小文件
set hive.merge.size.per.task = 256*1000*1000 ##合並文件的大小
set mapred.max.split.size=256000000; ##每個 Map 最大分割大小
set mapred.min.split.size.per.node=1; ##一個節點上 split 的最少值
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat; ##執行 Map 前進行小文件合並
配置Hive結果合並
SET hive.exec.dynamic.partition.mode=nonstrict;
SET hive.exec.max.dynamic.partitions=10000000;
SET hive.exec.max.dynamic.partitions.pernode=100000;
SET hive.merge.tezfiles=true;
-- 動態分區
insert overwrite table xxx PARTITION (dt)
select *
from xxx
where dt>='2017-02-01' and dt<'2017-04-01';
-- 靜態分區
nsert overwrite table xxx PARTITION (dt='2017-02-01')
select
a1,a2,a3
from xxx
where dt='2017-02-01';
我們可以通過一些配置項來使Hive在執行結束后對結果文件進行合並:
hive.merge.mapfiles 在map-only job后合並文件,默認true
hive.merge.mapredfiles 在map-reduce job后合並文件,默認false
hive.merge.size.per.task 合並后每個文件的大小,默認256000000
hive.merge.smallfiles.avgsize 平均文件大小,是決定是否執行合並操作的閾值,默認16000000
Hive在對結果文件進行合並時會執行一個額外的map-only腳本,mapper的數量是文件總大小除以size.per.task參數所得的值,觸發合並的條件是:
根據查詢類型不同,相應的mapfiles/mapredfiles參數需要打開;
結果文件的平均大小需要大於avgsize參數的值。
示例:
-- map-red job,5個reducer,產生5個60K的文件。
create
table dw_stage.zj_small
as
select paid, count (*)
from dw_db.dw_soj_imp_dtl
where log_dt = '2014-04-14'
group
by paid;
-- 執行額外的map-only job,一個mapper,產生一個300K的文件。
set hive.merge.mapredfiles=
true;
create
table dw_stage.zj_small
as
select paid, count (*)
from dw_db.dw_soj_imp_dtl
where log_dt = '2014-04-14'
group
by paid;
-- map-only job,45個mapper,產生45個25M左右的文件。
create
table dw_stage.zj_small
as
select *
from dw_db.dw_soj_imp_dtl
where log_dt = '2014-04-14' ;
-- 執行額外的map-only job,4個mapper,產生4個250M左右的文件。
set hive.merge.smallfiles.avgsize=100000000;
create
table dw_stage.zj_small
as
select *
from dw_db.dw_soj_imp_dtl
where log_dt = '2014-04-14';
壓縮文件的處理
對於輸出結果為壓縮文件形式存儲的情況,要解決小文件問題,如果在Map輸入前合並,對輸出的文件存儲格式並沒有限制。但是如果使用輸出合並,則必須配合SequenceFile來存儲,否則無法進行合並,以下是示例:
set mapred.output.compression.
type=BLOCK;
set hive.exec.compress.output=
true;
set mapred.output.compression.codec=org.apache.hadoop.io.compress.LzoCodec;
set hive.merge.smallfiles.avgsize=100000000;
drop
table if
exists dw_stage.zj_small;
create
table dw_stage.zj_small
STORED
AS SEQUENCEFILE
as
select *
from dw_db.dw_soj_imp_dtl
where log_dt = '2014-04-14' ;
使用HAR歸檔文件
Hadoop的歸檔文件格式也是解決小文件問題的方式之一。而且Hive提供了原生支持:
set hive.archive.enabled=
true;
set hive.archive.har.parentdir.settable=
true;
set har.partfile.size=1099511627776;
ALTER
TABLE srcpart ARCHIVE PARTITION(ds= '2008-04-08', hr= '12' );
ALTER
TABLE srcpart UNARCHIVE PARTITION(ds= '2008-04-08', hr= '12' );
Hadoop Archive是一種特殊的歸檔格式,Hadoop Archive映射到文件系統目錄,一個HAR以擴展名.har結尾,一個HAR目錄包含元數據(以_index和_masterindex的形式)和data(part- *)文件。 _index文件包含文件名稱,這些文件時歸檔的一部分,並且包含這些文件在歸檔中的位置。
hadoop archive -archiveName name -p <parent> <src>* <dest>
-archiveName用來指定你想創建的歸檔名稱,parent用來指定需要歸檔文件的相對路徑的父參數(支持正則表達式)。需要注意的是歸檔是一個map/reduce。如下使用例子:
hadoop archive -archiveName zoo.har -p /foo/bar a/b/c e/f/g /outputdir
在以上例子中/foo/bar是a/b/c, e/f/g的父目錄。如果你想直接對一個目錄進行歸檔,可以直接使用如下命令:
hadoop archive -archiveName zoo.har -p /foo/bar /outputdir
檔案(archive)屬於文件系統層,使用不同的URI,在檔案中可以使用所有的fs shell命令,需要注意的是檔案是不可變的,不能夠被刪除,重命名和創建。HAR的URI格式如下所示:
har://scheme-hostname:port/archivepath/fileinarchive