先看一下這個(gè)圖Mapper-Shuffle-Reducer
輸入分片(Input Split):在進(jìn)行map計(jì)算之前夺荒,MapReduce會(huì)根據(jù)輸入文件計(jì)算輸入分片(input split)力图,每個(gè)輸入分片(input split)針對(duì)一個(gè)map任務(wù),輸入分片(input split)存儲(chǔ)的并非數(shù)據(jù)本身刚陡,而是一個(gè)分片長(zhǎng)度和一個(gè)記錄數(shù)據(jù)的位置的數(shù)組,對(duì)應(yīng)到Java的類InputSplit類。
Hadoop 2.x默認(rèn)的block大小是128MB翠储,Hadoop 1.x默認(rèn)的block大小是64MB,可以在hdfs-site.xml中設(shè)置dfs.block.size橡疼,注意單位是Byte援所。
分片大小范圍可以在mapred-site.xml中設(shè)置,參數(shù)為mapred.min.split.size和mapred.max.split.size欣除,其中minSplitSize大小默認(rèn)為1B住拭,maxSplitSize大小默認(rèn)為L(zhǎng)ong.MAX_VALUE = 9223372036854775807
那么分片到底是多大呢?
minSize=max{minSplitSize,mapred.min.split.size}
maxSize=mapred.max.split.size
splitSize=max{minSize,min{maxSize,blockSize}}
我們?cè)賮?lái)看一下源碼
這里可以得出:在我們沒(méi)有設(shè)置分片的范圍的時(shí)候,分片大小是由block塊大小決定的滔岳,和它的大小一樣杠娱。比如把一個(gè)258MB的文件上傳到HDFS上,假設(shè)block塊大小是128MB谱煤,那么它就會(huì)被分成三個(gè)block塊摊求,還有與之對(duì)應(yīng)產(chǎn)生三個(gè)InputSplit,所以最終會(huì)產(chǎn)生三個(gè)map task刘离。
我又發(fā)現(xiàn)了另一個(gè)問(wèn)題室叉,第三個(gè)block塊里存的文件大小只有2MB,而它的block塊大小是128MB硫惕,那它實(shí)際占用Linux file system的多大空間茧痕?
答案是實(shí)際的文件大小,而非一個(gè)塊的大小疲憋。
有大神已經(jīng)驗(yàn)證這個(gè)答案了:http://blog.csdn.net/samhacker/article/details/23089157
-
往hdfs里面添加新文件前凿渊,hadoop在linux上面所占的空間為 464 MB:
往hdfs里面添加大小為2673375 byte(大概2.5 MB)的文件:
2673375 derby.jar此時(shí),hadoop在linux上面所占的空間為 467 MB——增加了一個(gè)實(shí)際文件大小(2.5 MB)的空間缚柳,而非一個(gè)block size(128 MB):
- 使用hadoop dfs -stat查看文件信息:
這里就很清楚地反映出: 文件的實(shí)際大小(file size)是2673375 byte埃脏, 但它的block size是128 MB。
5秋忙、通過(guò)NameNode的web console來(lái)查看文件信息:
結(jié)果是一樣的: 文件的實(shí)際大小(file size)是2673375 byte彩掐, 但它的block size是128 MB。
6灰追、不過(guò)使用‘hadoop fsck’查看文件信息堵幽,看出了一些不一樣的內(nèi)容—— ‘1(avg.block size 2673375 B)’:
值得注意的是,結(jié)果中有一個(gè) ‘1(avg.block size 2673375 B)’的字樣弹澎。這里的 'block size' 并不是指平常說(shuō)的文件塊大小(Block Size)—— 后者是一個(gè)元數(shù)據(jù)的概念朴下,相反它反映的是文件的實(shí)際大小(file size)。
以下是Hadoop Community的專家給出的回復(fù):
“The fsck is showing you an "average blocksize", not the block size metadata attribute of the file like stat shows. In this specific case, the average is just the length of your file, which is lesser than one whole block.”
最后一個(gè)問(wèn)題是: 如果hdfs占用Linux file system的磁盤空間按實(shí)際文件大小算苦蒿,那么這個(gè)”塊大小“有必要存在嗎殴胧?
其實(shí)塊大小還是必要的,一個(gè)顯而易見(jiàn)的作用就是當(dāng)文件通過(guò)append操作不斷增長(zhǎng)的過(guò)程中佩迟,可以通過(guò)來(lái)block size決定何時(shí)split文件团滥。
以下是Hadoop Community的專家給出的回復(fù):
“The block size is a meta attribute. If you append tothe file later, it still needs to know when to split further - so it keeps that value as a mere metadata it can use to advise itself on write boundaries.”
補(bǔ)充:我還查到這樣一段話
原文地址:http://blog.csdn.net/lylcore/article/details/9136555
(Hadoop1.x版本中)一個(gè)split的大小是由goalSize, minSize, blockSize這三個(gè)值決定的。computeSplitSize的邏輯是报强,先從goalSize和blockSize兩個(gè)值中選出最小的那個(gè)(比如一般不設(shè)置map數(shù)灸姊,這時(shí)blockSize為當(dāng)前文件的塊size,而goalSize是文件大小除以用戶設(shè)置的map數(shù)得到的秉溉,如果沒(méi)設(shè)置的話力惯,默認(rèn)是1)碗誉。
hadooop提供了一個(gè)設(shè)置map個(gè)數(shù)的參數(shù)mapred.map.tasks,我們可以通過(guò)這個(gè)參數(shù)來(lái)控制map的個(gè)數(shù)夯膀。但是通過(guò)這種方式設(shè)置map的個(gè)數(shù)诗充,并不是每次都有效的。
原因是mapred.map.tasks只是一個(gè)hadoop的參考數(shù)值诱建,最終map的個(gè)數(shù)蝴蜓,還取決于其他的因素。為了方便介紹俺猿,先來(lái)看幾個(gè)名詞:
block_size : hdfs的文件塊大小茎匠,Hadoop1.x默認(rèn)為64M,Hadoop2.x默認(rèn)為128M押袍,可以通過(guò)參數(shù)dfs.block.size設(shè)置
total_size : 輸入文件整體的大兴忻啊(Hadoop1.x版本)
input_file_num : 輸入文件的個(gè)數(shù)
默認(rèn)map個(gè)數(shù)
如果不進(jìn)行任何設(shè)置,默認(rèn)的map個(gè)數(shù)是和blcok_size相關(guān)的谊惭。
default_num = total_size / block_size;期望大小
可以通過(guò)參數(shù)mapred.map.tasks來(lái)設(shè)置程序員期望的map個(gè)數(shù)汽馋,但是這個(gè)個(gè)數(shù)只有在大于default_num的時(shí)候,才會(huì)生效圈盔。
goal_num = mapred.map.tasks;設(shè)置處理的文件大小
可以通過(guò)mapred.min.split.size 設(shè)置每個(gè)task處理的文件大小豹芯,但是這個(gè)大小只有在大于block_size的時(shí)候才會(huì)生效。
split_size = max(mapred.min.split.size, block_size);
split_num = total_size / split_size;計(jì)算的map個(gè)數(shù)
compute_map_num = min(split_num, max(default_num, goal_num))
除了這些配置以外驱敲,mapreduce還要遵循一些原則铁蹈。 mapreduce的每一個(gè)map處理的數(shù)據(jù)是不能跨越文件的,也就是說(shuō)min_map_num >= input_file_num众眨。 所以握牧,最終的map個(gè)數(shù)應(yīng)該為:
final_map_num = max(compute_map_num, input_file_num)
經(jīng)過(guò)以上的分析,在設(shè)置map個(gè)數(shù)的時(shí)候娩梨,可以簡(jiǎn)單的總結(jié)為以下幾點(diǎn):
1)如果想增加map個(gè)數(shù)沿腰,則設(shè)置mapred.map.tasks 為一個(gè)較大的值。
2)如果想減小map個(gè)數(shù)狈定,則設(shè)置mapred.min.split.size 為一個(gè)較大的值颂龙。
3)如果輸入中有很多小文件,依然想減少map個(gè)數(shù)掸冤,則需要將小文件merger為大文件厘托,然后使用準(zhǔn)則2友雳。