-
1. 三大过程
- Map侧Shuffle
- Reduce侧Shuffle -
2. 六大组件
- InputFormat
- OutputFormat
- Serilizer
- Comparator
- Combiner
- Partitioner - 3. Mapreduce调优
1. 三大过程
上一节演示了最简单的MR任务的编写,可以看到其实很简单,说简单点就是套模板。但是要想用好hadoop这一利器,需要了解更多执行细节,在基本概念中已经说过mapreduce包括三大过程,最常见的一幅总结图如下:
这里包括
- Map 读入文件块,分割成指定键值对
- Shuffle map输出的键值对分组排序后输出到磁盘,提供给reduce作为输入
- Reduce 读入shuffle后的键值对处理
广义来讲只有Map和Reduce,但是和用户需要编程处理的map/reduce过程相比,map输出到reduce输入中间有大量处理过程,都属于shuffle,也有人区分map侧shuffle和reduce侧shuffle,参考下图,详细描述这两个shuffle过程。
Map侧Shuffle
- map输出不会直接输出到磁盘,会先写到一个环形缓冲区,缓冲区大小参数io.sort.mb设置,当超过一定阈值时(io.sort.spill.percent),一个后台线程会把缓冲区内容溢写到指定目录(mapred.local.dir)下的一个新建文件
- 写磁盘时会先按照指定的分组器分组Partitioner,默认是HashPartitioner。示例按照键值的奇偶分成两组,分组数和reduce数量相同。
- 然后按照指定指定的比较器Comparator排序键值对,示例按照键的大小排序。
- 如果指定了组合器Combiner,会先将输出的数据通过Combiner先做处理,这样会减少传输数据量,加快处理速度。
- 最终磁盘上存在一个个小的磁盘溢写文件,这些文件归并排序成一个大的分组排序好的文件
Reduce侧Shuffle
- 在reduce侧通过http拉取map侧对应的分组数据,数据序列器Serilizer序列化后传输以减少传输压力
- 拉取的数据先到缓冲区中排序合并
- 如果数据量太大,采用和之前一样的策略,先写到磁盘上一个小文件,然后再做归并排序,这里数据排序主要就是为了归并排序
到此,mapreduce的过程应该解析非常清楚了,可以发现,在shuffle过程中存在大量的磁盘读写操作,因此相对较慢,Spark等计算模型针对此尽量把中间shuffle过程放在内存中处理以加快速度,但是也应该看到,由于采用基于磁盘的归并方法,mapreduce可以廉价的成本支持超大规模的数据处理,这也是mapreduce的价值所在。
这三大过程可以用网友的一幅图完全概括,如下:
2. 六大组件
mapreduce允许我们编写map/reduce过程处理代码外,还允许我们定制如上的三大过程细节,姑且称这些细节控制为组件编程。除了上述过程分析提到的外,mapreduce还包括InputFormat和OutputFormat,一共是如下六大组件:
InputFormat
针对不同数据源选择不同InputFormat实现读取输入到map,决定了输入数据如何解析,默认TextInputFormat,按行解析文本输入,键为偏移量,值为行数据。
OutputFormat
输出数据处理,决定数据如何输出,可以选择不同的OutputFormat实现来输出。
Serilizer
决定传输数据如何序列化和反序列化,需要实现Writable接口的write和readFields。
Comparator
定制键值对如何排序,需要实现Comparable接口的compareTo。
Combiner
定制键值对如何在到达Reduce前先本地reduce一遍,减少数据传输量,需要实现Reducer接口的reduce,一般函数内容和Reduce过程一样。
Partitioner
定制如何分组键值对,默认是HashPartitioner,需要实现Partitioner接口的getPartition,一般不需要定制。
后面会分别讲这些组件的编程实现。
3. Mapreduce调优
关于这个问题,不会具体展开,《hadoop权威指南(第四版)》已经总结的很好,便于理解的话可从如下几点考虑
- 充足的资源,包括map/reduce数量,对应的cpu/mem/java opts配置
- 足够快的传输,压缩/序列化/中间combiner排序/map join等
- 没有短板,shuffle过程调优,解决数据倾斜
如下对应书中一个表供参考:
原创,转载请注明来自