原文地址:
MapReduce Input Split(輸入分/切片)詳解
結(jié)論:
經(jīng)過以上的分析,在設(shè)置map個(gè)數(shù)的時(shí)候,可以簡單的總結(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。
看了很多博客,感覺沒有一個(gè)說的很清楚,所以我來整理一下。
先看一下這個(gè)圖
輸入分片(Input Split):
在進(jìn)行map計(jì)算之前,mapreduce會(huì)根據(jù)輸入文件計(jì)算輸入分片(input split),
每個(gè)輸入分片(input split)針對一個(gè)map任務(wù),
輸入分片(input split)存儲(chǔ)的并非數(shù)據(jù)本身,
而是一個(gè)分片長度和一個(gè)記錄數(shù)據(jù)的位置的數(shù)組。
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è)置,
mapred.min.split.size
mapred.max.split.size,
minSplitSize大小默認(rèn)為1B,
maxSplitSize大小默認(rèn)為Long.MAX_VALUE = 9223372036854775807
那么分片到底是多大呢?
minSize=max{minSplitSize,mapred.min.split.size}
maxSize=mapred.max.split.size
splitSize=max{minSize,min{maxSize,blockSize}}
我們再來看一下源碼
所以在我們沒有設(shè)置分片的范圍的時(shí)候,分片大小是由block塊大小決定的,和它的大小一樣。
比如把一個(gè)258MB的文件上傳到HDFS上,
假設(shè)block塊大小是128MB,
那么它就會(huì)被分成三個(gè)block塊,
與之對應(yīng)產(chǎn)生三個(gè)split
所以最終會(huì)產(chǎn)生三個(gè)map task。
我又發(fā)現(xiàn)了另一個(gè)問題,第三個(gè)block塊里存的文件大小只有2MB,而它的block塊大小是128MB,那它實(shí)際占用Linux file system的多大空間?**
答案是實(shí)際的文件大小,而非一個(gè)塊的大小。
有大神已經(jīng)驗(yàn)證這個(gè)答案了:
http://blog.csdn.net/samhacker/article/details/23089157
**
1、往hdfs里面添加新文件前,hadoop在Linux上面所占的空間為 464 MB:
2、往hdfs里面添加大小為2673375 byte(大概2.5 MB)的文件:
2673375 derby.jar
3、此時(shí),hadoop在linux上面所占的空間為 467 MB——增加了一個(gè)實(shí)際文件大小(2.5 MB)的空間,而非一個(gè)block size(128 MB):
4、使用hadoop dfs -stat查看文件信息:
這里就很清楚地反映出: 文件的實(shí)際大小(file size)是2673375 byte, 但它的block size是128 MB。
5、通過NameNode的web console來查看文件信息:
結(jié)果是一樣的: 文件的實(shí)際大小(file size)是2673375 byte, 但它的block size是128 MB。
6、不過使用‘hadoop fsck’查看文件信息,看出了一些不一樣的內(nèi)容—— ‘1(avg.block size 2673375 B)’:
值得注意的是,結(jié)果中有一個(gè) ‘1(avg.block size 2673375 B)’的字樣。這里的 'block size' 并不是指平常說的文件塊大小(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è)問題是: 如果hdfs占用Linux file system的磁盤空間按實(shí)際文件大小算,那么這個(gè)”塊大小“有必要存在嗎?
其實(shí)塊大小還是必要的,一個(gè)顯而易見的作用就是當(dāng)文件通過append操作不斷增長的過程中,可以通過來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
一個(gè)split的大小是由goalSize
, minSize
, blockSize
這三個(gè)值決定的。
computeSplitSize的邏輯是,
先從goalSize和blockSize兩個(gè)值中選出最小的那個(gè)
(比如一般不設(shè)置map數(shù),這時(shí)blockSize為當(dāng)前文件的塊size,
而goalSize是文件大小除以用戶設(shè)置的map數(shù)得到的,如果沒設(shè)置的話,默認(rèn)是1)。
hadooop提供了一個(gè)設(shè)置map個(gè)數(shù)的參數(shù)mapred.map.tasks,
我們可以通過這個(gè)參數(shù)來控制map的個(gè)數(shù)。
但是通過這種方式設(shè)置map的個(gè)數(shù),并不是每次都有效的。
原因是mapred.map.tasks只是一個(gè)hadoop的參考數(shù)值,
最終map的個(gè)數(shù),還取決于其他的因素。
為了方便介紹,先來看幾個(gè)名詞:
block_size : hdfs的文件塊大小,默認(rèn)為64M,可以通過參數(shù)dfs.block.size設(shè)置
total_size : 輸入文件整體的大小
input_file_num : 輸入文件的個(gè)數(shù)
(1)默認(rèn)map個(gè)數(shù)
如果不進(jìn)行任何設(shè)置,默認(rèn)的map個(gè)數(shù)是和blcok_size相關(guān)的。
default_num = total_size / block_size;
(2)期望大小
可以通過參數(shù)mapred.map.tasks來設(shè)置程序員期望的map個(gè)數(shù),但是這個(gè)個(gè)數(shù)只有在大于default_num的時(shí)候,才會(huì)生效。
goal_num = mapred.map.tasks;
(3)設(shè)置處理的文件大小
可以通過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;
(4)計(jì)算的map個(gè)數(shù)
compute_map_num = min(split_num, max(default_num, goal_num))
除了這些配置以外,mapreduce還要遵循一些原則。
mapreduce的每一個(gè)map處理的數(shù)據(jù)是不能跨越文件的,
也就是說min_map_num >= input_file_num。
所以,最終的map個(gè)數(shù)應(yīng)該為:
final_map_num = max(compute_map_num, input_file_num)
經(jīng)過以上的分析,在設(shè)置map個(gè)數(shù)的時(shí)候,可以簡單的總結(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。