title: 【MapReduce详解及源码解析(一)】——分片输入、Mapper及Map端Shuffle过程
date: 2018-12-03 21:12:42
tags: Hadoop
categories: 大数据
toc: true
点击查看我的博客:Josonlee’s Blog
版权声明:本文为博主原创文章,未经博主允许不得转载(https://blog.csdn.net/lzw2016/)
之前在看这一部分内容时,也挺烦的,细读一遍《Hadoop 海量数据处理·范东来著》书和老师给的若干Demo代码,自己再看看MapReduce的部分源码后,感触挺深的。把自己所领会的记录在这里吧,文章挺长,一次可能写不完(写不完下次再说吧)
前瞻
用户向Hadoop提交的最小单位是MR作业job,MR计算的最小单位是任务task。job分为多个task,task又分map任务,reduce任务
在Hadoop1.0版本,客户端向Hadoop提交作业,JobTracker会将该作业拆分为多个任务,并根据心跳信息交由空闲的TaskTracker 启动。一个TaskTracker能够启动的任务数量是由TaskTracker 配置的任务槽(slot) 决定。槽是Hadoop的计算资源的表示模型,Hadoop将各个节点上的多维度资源(CPU、内存等)抽象成一维度的槽,这样就将多维度资源分配问题转换成维度的槽 分配的问题。在实际情况中, Map任务和Reduce任务需要的计算资源不尽相同,Hadoop又将槽分成Map槽和Reduce槽,并且Map任务只能使用Map槽,Reduce任务只能使用Reduce槽。
这样做性能会很低,所以在Hadoop2.0版本,资源管理调度框架改为了Yarn,但MR任然作为计算框架存在
MapReduce过程概览
这张图出处不知,我也就随便用了
一、输入数据分片并转化为键值对
在进行map计算之前,mapreduce会根据输入文件计算输入分片(input split), 每个输入分片(InputSplit)针对一个map任务, 输入分片(input split)存储的并非数据本身, 而是逻辑上一个分片长度和一个记录数据的位置的数组。 默认分片等同于块大小,分片大小对MR性能影响很大,尽量和block大小相近可以提供map任务计算的数据本地性
可以设置一个map任务的参考个数值,见参数mapred.map.tasks,只是参考具体还是取决于分片数
下面源码中会看到分片大小具体是如何设定的
MapReduce Input Split(输入分/切片)详解,这篇文章对分片这一块总结的挺不错
看下源码中InputSplit的实现,见InputFormat数据格式转换接口
如图,左侧是实现该接口的几个格式化数据的类,右侧是该接口的两个抽象方法:getSplits是将数据切分成若干个分片,createRecordReader是将输入的分片解析成键值对(key-value),键是偏移量,值是该行的内容
FileInputFormat类及其子类的相关源码解析
继续看下去,看下用的比较多的FileInputFormat类的源码
- 分片大小计算
// 计算分片大小
protected long computeSplitSize(long blockSize, long minSize,
long maxSize) {
return Math.max(minSize, Math.min(maxSize, blockSize));
}
代码中的minSize、maxSize定义
minSize=max{minSplitSize,mapred.min.split.size}
maxSize=mapred.max.split.size
blockSize是块大小,所以就是用设置中这三个参数而定的
- 数据分片
// 数据分片
public List<InputSplit> getSplits(JobContext job) throws IOException {
Stopwatch sw = new Stopwatch().start();
long minSize = Math.max(getFormatMinSplitSize(), getMinSplitSize(job));
long maxSize = getMaxSplitSize(job);
// 此处省略
if (isSplitable(job, path)) {