前言
MapReduce的源码分析是基于Hadoop1.2.1基础上进行的代码分析。
什么是InputSplit
InputSplit是指分片,在MapReduce当中作业中,作为map task最小输入单位。分片是基于文件基础上出来的而来的概念,通俗的理解一个文件可以切分为多少个片段,每个片段包括了<文件名,开始位置,长度,位于哪些主机>等信息。在MapTask拿到这些分片后,会知道从哪开始读取数据。Job提交时如何获取到InputSplit
以org.apache.hadoop.mapred包中的FileInputFormat为例(因为该类作为其他文件类型的基类),内部实现了如何获取分片,通过分析代码,以便知晓文件是如何被切片的。
public InputSplit[] getSplits(JobConf job, int numSplits)
throwsIOException {
//获取文件列表的状态,底层通过HDFS客户端的//DistributedFileSystem.getFileStatus获取到文件的状态(文件长度,访问时间,权限,块大小,副本数等信息)
FileStatus[] files = listStatus(job);
// 保存输入的文件的文件个数
job.setLong(NUM_INPUT_FILES, files.length);
//计算所有文件的总长度
longtotalSize = 0; // compute total size
for(FileStatus file: files) { // check we have valid files
if(file.isDir()) {
throw new IOException("Not a file: "+ file.getPath());
}
totalSize += file.getLen();
}
// 计算出目标长度,通过总长度和用户指定的map task的个数相除得到
longgoalSize = totalSize / (numSplits == 0 ? 1 : numSplits);
// 获取用户配置文件中指定的最小split的长度,默认为1,如果不希望按默认计算出的大//小进行分片,则可以指定最小切分的大小,当这个值大于计算出的分片大小,则会以此为准。
longminSize = Math.max(job.getLong("mapred.min.split.size", 1),
minSplitSize);
// 保存后续生成的split
ArrayList<FileSplit> splits = new ArrayList<FileSplit>(numSplits);
NetworkTopology clusterMap = new NetworkTopology();
//对每个文件进行切片
for(FileStatus file: files) {
Path path = file.getPath();
FileSystem fs = path.getFileSystem(job);
longlength = file.getLen();
// 获取到整个文件的所有block的位置信息
BlockLocation[] blkLocations = fs.getFileBlockLocations(file, 0,length);
// 文件长度不为0,且能被切分(二进制文件总是不允许切分)
if((length != 0) && isSplitable(fs, path))