hadoop2.7作业提交详解之文件分片
在前面一篇文章中(hadoop2.7之作业提交详解(上))中涉及到文件的分片。
JobSubmitter.submitJobInternal方法中调用了
int maps = writeSplits(job, submitJobDir); //设置map的数量,而map的数量是根据文件的大小和分片的大小,以及文件的数量决定的
接下来我们看一下JobSubmitter.writeSplits方法:
private int writeSplits(org.apache.hadoop.mapreduce.JobContext job,
Path jobSubmitDir) throws IOException,
InterruptedException, ClassNotFoundException {
JobConf jConf = (JobConf)job.getConfiguration();
int maps;
if (jConf.getUseNewMapper()) {
maps = writeNewSplits(job, jobSubmitDir); //这里我们使用新的方式
} else {
maps = writeOldSplits(jConf, jobSubmitDir);
}
return maps;
}
接下来继续看JobSubmitter.writeNewSplits方法:
private <T extends InputSplit>
int writeNewSplits(JobContext job, Path jobSubmitDir) throws IOException,
InterruptedException, ClassNotFoundException {
Configuration conf = job.getConfiguration();
InputFormat<?, ?> input =
ReflectionUtils.newInstance(job.getInputFormatClass(), conf); //输入对象,InputFormat是个抽象类 List<InputSplit> splits = input.getSplits(job); //调用InputFormat实现类的getSplits方法
T[] array = (T[]) splits.toArray(new InputSplit[splits.size()]); // sort the splits into order based on size, so that the biggest
// go first
Arrays.sort(array, new SplitComparator()); //对切片的大小进行排序,最大的放最前面
JobSplitWriter.createSplitFiles(jobSubmitDir, conf,
jobSubmitDir.getFileSystem(conf), array);//创建Split文件
return array.length;
}
接下来看一下InputFormat这个抽象类:
public abstract class InputFormat<K, V> {
//用来返回分片结果
public abstract
List<InputSplit> getSplits(JobContext context
) throws IOException, InterruptedException;
//RecordReader是用来从一个输入分片中读取一个一个的K-V对的抽象类,我们可以将其看作是在InputSplit上的迭代器。
//最主要的方法就是nextKeyvalue()方法,由它获取分片上的下一个K-V 对。
public abstract
RecordReader<K,V> createRecordReader(InputSplit split,
TaskAttemptContext context
) throws IOException,
InterruptedException;
}
接下来我们继续看这个抽象类的实现类:
public class TextInputFormat extends FileInputFormat;
public abstract class FileInputFormat<K, V> extends InputFormat;
public abstract class InputFormat。
由于TextInputFormat从抽象类FileInputFormat中继承,所以大部分的方法都来自于FileInputFormat类,TextInputFormat类只重写了两个方法:如下:
public class TextInputFormat extends FileInputFormat<LongWritable, Text> {
@Override
public RecordReader<LongWritable, Text>
createRecordReader(InputSplit split,
TaskAttemptContext context) {
String delimiter = context.getConfiguration().get(
"textinputformat.record.delimiter");
byte[] recordDelimiterBytes = null;
if (null != delimiter)
recordDelimiterBytes = delimiter.getBytes(Charsets.UTF_8);
//LineRecordReader由一个FileSplit构造出来,start是这个FileSplit的起始位置,pos是当前读取分片的位置,
//end是分片结束位置,in是打开的一个读取这个分片的输入流,它是使用这个FileSplit对应的文件名来打开的。
//key和value则分别是每次读取的K-V对。然后我们还看到可以利用getProgress()来跟踪读取分片的进度,
//这个函数就是根据已经读取的K-V对占总K-V对的比例来显示进度的
return new LineRecordReader(recordDelimiterBytes);
}
@Override
protected boolean isSplitable(JobContext context, Path file) {
//如果是压缩文件就不切分,非压缩文件就切分。
final CompressionCodec codec =
new CompressionCodecFactory(context.getConfiguration()).getCodec(file);
if (null == codec) {
return true;
}
return codec instanceof SplittableCompressionCodec;
}
}
我们在返回到JobSubmitter.writeNewSplits方法中,有List<InputSplit> splits = input.getSplits(job);主要是调用了TextInputFormat.getSplits()方法,而TextInputFormat继承了FileInputFormat类,所以调用的就是FileInputFormat.getSplits()方法:
public List<InputSplit> getSplits(JobContext job) throws IOException {
StopWatch sw = new StopWatch().start();//用来计算纳秒级别的时间
long minSize = Math.max(getFormatMinSplitSize(), getMinSplitSize(job)); //最小值默认为1
long maxSize = getMaxSplitSize(job); //最大值为long的最大值,默认为0x7fffffffffffffffL
// generate splits
List<InputSplit> splits = new ArrayList<InputSplit>();
List<FileStatus> files = listStatus(job); //获得所有的输入文件
for (FileStatus file: files) {
Path path = file.getPath(); //文件路径
long length = file.getLen(); //文件大小
if (length != 0) {
BlockLocation[] blkLocations;
if (file instanceof LocatedFileStatus) {//如果是个含有数据块位置信息的文件
blkLocations = ((LocatedFileStatus) file).getBlockLocations();
} else { //一般文件
FileSystem fs = path.getFileSystem(job.getConfiguration());
blkLocations = fs.getFileBlockLocations(file, 0, length);
}
if (isSplitable(job, path)) { //判断是否可以分片
long blockSize = file.getBlockSize(); //128M
long splitSize = computeSplitSize(blockSize, minSize, maxSize); //计算分片的大小,默认为128M
long bytesRemaining = length;
while (((double) bytesRemaining)/splitSize > SPLIT_SLOP) { //判断剩余文件大小是否大于128M*1.1
int blkIndex = getBlockIndex(blkLocations, length-bytesRemaining);//f返回每个分片起始位置
splits.add(makeSplit(path, length-bytesRemaining, splitSize,
blkLocations[blkIndex].getHosts(),
blkLocations[blkIndex].getCachedHosts()));
bytesRemaining -= splitSize; // 依次减去分片的大小,对剩余长度再次分片
}
// 多次分片后,最后的数据长度仍不为0但又不足一个分片大小
if (bytesRemaining != 0) {
int blkIndex = getBlockIndex(blkLocations, length-bytesRemaining);
splits.add(makeSplit(path, length-bytesRemaining, bytesRemaining,
blkLocations[blkIndex].getHosts(),
blkLocations[blkIndex].getCachedHosts()));
}
//不可分,则把整个文件作为一个分片
} else { // not splitable
splits.add(makeSplit(path, 0, length, blkLocations[0].getHosts(),
blkLocations[0].getCachedHosts()));
}
} else {
//创建空的分片
//Create empty hosts array for zero length files
splits.add(makeSplit(path, 0, length, new String[0]));
}
}
// Save the number of input files for metrics/loadgen
job.getConfiguration().setLong(NUM_INPUT_FILES, files.size()); //设置参数NUM_INPUT_FILES
sw.stop();
if (LOG.isDebugEnabled()) {
LOG.debug("Total # of splits generated by getSplits: " + splits.size()
+ ", TimeTaken: " + sw.now(TimeUnit.MILLISECONDS));
}
return splits;
}
//public class FileSplit extends InputSplit implements Writable {
// private Path file;//输入文件路径
// private long start;//分片在文件中的位置(起点)
// private long length;//分片长度
// private String[] hosts;//这个分片所在数据块的多个复份所在节点
// private SplitLocationInfo[] hostInfos;//每个数据块复份所在节点,以及是否缓存
//}
//makeSplit方法存放的分片格式
protected FileSplit makeSplit(Path file, long start, long length,
String[] hosts, String[] inMemoryHosts) {
return new FileSplit(file, start, length, hosts, inMemoryHosts);
}
//计算分片的大小
protected long computeSplitSize(long blockSize, long minSize,
long maxSize) {
return Math.max(minSize, Math.min(maxSize, blockSize));
}
通过FileInputFormat.getSplits(),可以返回一个存放分片的ArraryList,接下继续回到JobSubmitter.writeNewSplits方法中:
接下来将ArrayList转换为数组,并根据分片的大小排序。然后调用JobSplitWriter.createSplitFiles()方法创建split文件。最后返回数组的长度,也就是map的个数。
hadoop2.7作业提交详解之文件分片的更多相关文章
- hadoop2.7之作业提交详解(上)
根据wordcount进行分析: import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; impo ...
- hadoop2.7之作业提交详解(下)
接着作业提交详解(上)继续写:在上一篇(hadoop2.7之作业提交详解(上))中已经讲到了YARNRunner.submitJob() [WordCount.main() -> Job.wai ...
- [转]文件IO详解(二)---文件描述符(fd)和inode号的关系
原文:https://www.cnblogs.com/frank-yxs/p/5925563.html 文件IO详解(二)---文件描述符(fd)和inode号的关系 ---------------- ...
- MFC中文件对话框类CFileDialog详解及文件过滤器说明
当前位置 : 首页 » 文章分类 : 开发 » MFC中文件对话框类CFileDialog详解及文件过滤器说明 上一篇 利用OpenCV从摄像头获得图像的坐标原点是在左下角 下一篇 Word中为 ...
- ***PHP $_FILES函数详解 + PHP文件上传 move_uploaded_file() 参数的正确写法
PHP $_FILES函数详解 在PHP中上传一个文件建一个表单要比ASP中灵活得多.具体的看代码. 如: 复制代码代码如下: <form enctype="multipart/fo ...
- hadoop2——新MapReduces——yarm详解
YARN总体上仍然是Master/Slave结构,在整个资源管理框架中,ResourceManager为Master,NodeManager为Slave,ResourceManager负责对各个Nod ...
- CentOS7下用jdk1.7编译hadoop-2.7.1全过程详解
说实话,本人编译hadoop的过程比较曲折,但收获也很多,下面系统介绍一下CentOS7下编译hadoop-2.7.1的全过程吧. 先说明,32位Linux操作系统可以直接下载编译好的hadoop使用 ...
- hadoop2—namenode—HA原理详解
在hadoop1中NameNode存在一个单点故障问题,也就是说如果NameNode所在的机器发生故障,那么整个集群就将不可用(hadoop1中有个SecorndaryNameNode,但是它并不是N ...
- 详解bootstrap-fileinput文件上传控件的亲身实践
经理让我帮服务器开发人员开发一个上传文件功能界面,我就想着以前使用过bootstrap-fileinput插件进行文件上传,很不错.赶紧就撸起来了. 1.下载压缩包.插件地址https://githu ...
随机推荐
- 论文阅读 <Relocalization, Global Optimization and Map Merging for Monocular Visual-Inertial SLAM>
看了一下港科的基于vins拓展的论文<relocalization, global optimization and merging for vins>,在回环的实现部分总体没有什么变化, ...
- 使用WebService发布soap接口,并实现客户端的https验证
什么是https HTTPS其实是有两部分组成:HTTP + SSL / TLS, 也就是在HTTP上又加了一层处理加密信息的模块,并且会进行身份的验证. 如何进行身份验证? 首先我们要明白什么是对称 ...
- java学习笔记系列整理说明
java学习笔记系列整理说明 陆陆续续也巩固学习java基础也有一段时间了,这里整理了一些我认为比较的重要的知识点,供自己或者读者以后回顾和学习.这是一个学习笔记系列,有自己的整理重新撰写的部分, ...
- 【HDU - 1043】Eight(反向bfs+康托展开)
Eight Descriptions: 简单介绍一下八数码问题:在一个3×3的九宫格上,填有1~8八个数字,空余一个位置,例如下图: 1 2 3 4 5 6 7 8 在上图中,由于右下角位置是空的 ...
- Excel催化剂开源第47波-Excel与PowerBIDeskTop互通互联之第一篇
当国外都在追求软件开源,并且在GitHub等平台上产生了大量优质的开源代码时,但在国内却在刮着一股收割小白智商税的知识付费热潮,实在可悲. 互联网的精神乃是分享,让分享带来更多人的受益. 在Power ...
- [剑指offer] 34. 第一个只出现一次的字符
题目描述 在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写). 一次遍历存储到哈希表 一次 ...
- [leetcode] 87. Scramble String (Hard)
题意: 判断两个字符串是否互为Scramble字符串,而互为Scramble字符串的定义: 字符串看作是父节点,从字符串某一处切开,生成的两个子串分别是父串的左右子树,再对切开生成的两个子串继续切开, ...
- .NET Core CSharp初级篇 1-6 类的多态与继承
.NET Core CSharp初级篇 1-6 本节内容为类的多态与继承 简介 终于讲到了面向对象三大特性中的两大特性--继承与多态.通过继承与多态,我们能很好的将类的拓展性发挥到了极致.在下面的内容 ...
- <<Modern CMake>> 翻译 1. CMake 介绍
<<Modern CMake>> 翻译 1. CMake 介绍 人们喜欢讨厌构建系统. 仅仅观看 CppCon17 上的演讲,就可以看到开发人员因为构建系统而闹笑话的例子. 这 ...
- ssm框架下的文件上传和文件下载
最近在做一个ssm的项目,遇到了添加附件和下载的功能,在网上查了很多资料,发现很多都不好用,经过摸索,发现了一套简便的方法,和大家分享一下. 1.在自己已经构建好的maven web项目中 pom. ...