MapReduce输入输出的处理流程及combiner
MapReduce 的输入输出
MapReduce 框架运转在<key,value> 键值对上,也就是说,框架把作业的输入看成是一组<key,value>键值对,同样也产生一组<key,value>键值对作为作业的输出,这两组键值对可能是不同的。
一个 MapReduce 作业的输入和输出类型如下图所示:可以看出在整个标准的流程中,会有三组<key,value>键值对类型的存在。
MapReduce的处理流程
1. Mapper任务执行过程详解
第一阶段是把输入目录下文件按照一定的标准逐个进行逻辑切片,形成切片规划。默认情况下,Split size = Block size。每一个切片由一个MapTask 处理。(getSplits)
第二阶段是对切片中的数据按照一定的规则解析成<key,value>对。默认规则是把每一行文本内容解析成键值对。key 是每一行的起始位置(单位是字节),value 是本行的文本内容。(TextInputFormat)
第三阶段是调用 Mapper 类中的 map 方法。上阶段中每解析出来的一个<k,v>,调用一次 map 方法。每次调用 map 方法会输出零个或多个键值对。
第四阶段是按照一定的规则对第三阶段输出的键值对进行分区。默认是只有一个区。分区的数量就是 Reducer 任务运行的数量。默认只有一个Reducer 任务。
第五阶段是对每个分区中的键值对进行排序。首先,按照键进行字典序排序,对于键相同的键值对,按照值进行排序。比如三个键值对<2,2>、<1,3>、<2,1>,键和值分别是整数。那么排序后的结果是<1,3>、<2,1>、<2,2>。
如果有第六阶段,那么进入第六阶段;如果没有,直接输出到文件中。
第六阶段是对数据进行局部聚合处理,也就是 combiner 处理。键相等的键值对会调用一次 reduce 方法。经过这一阶段,数据量会减少。 本阶段默认是没有的
2. Reducer 任务 任务 执行过程详解
第一阶段是 Reducer 任务会主动从 Mapper 任务复制其输出的键值对。Mapper 任务可能会有很多,因此 Reducer 会复制多个 Mapper 的输出。
第二阶段是把复制到 Reducer 本地数据,全部进行合并,即把分散的数据合并成一个大的数据。再对合并后的数据排序。
第三阶段是对排序后的键值对调用 reduce 方法。键相等的键值对调用一次reduce 方法,每次调用会产生零个或者多个键值对。最后把这些输出的键值对写入到 HDFS 文件中。
在整个MapReduce 程序的开发过程中,我们最大的工作量是覆盖map 函数和覆盖reduce 函数。
Mapreduce的combiner
每一个 map 都可能会产生大量的本地输出,Combiner 的作用就是对 map 端的输出先做一次合并,以减少在 map 和 reduce 节点之间的数据传输量,以提高网络 IO 性能,是 MapReduce 的一种优化手段之一。
- combiner 是 MR 程序中 Mapper 和 Reducer 之外的一种组件
- combiner 组件的父类就是 Reducer
- combiner 和 reducer 的区别在于运行的位置:
- Combiner 是在每一个 maptask 所在的节点运行
- Reducer 是接收全局所有 Mapper 的输出结果;
- combiner 的意义就是对每一个 maptask 的输出进行局部汇总,以减小网络传输量
- 具体实现步骤: 1、自定义一个 combiner 继承 Reducer,重写 reduce 方法
- combiner 能够应用的前提是不能影响最终的业务逻辑,而且,combiner 的输出 kv 应该跟 reducer 的输入 kv 类型要对应起来
- 2、在 job 中设置: job.setCombinerClass(CustomCombiner.class)
combiner本质上就是reduce 只不过是局部的reduce 进行局部汇总