MR 笔记二

1.Writable接口
在MR中使用对象

创建对象时需要实现Writable接口中的write()和readFields()方法  反序列化方法读顺序必须和写序列化方法的写顺序必须一致

2.MapTask运行机制详解
MR 笔记二_第1张图片
 

详细步骤:
1. 首先,读取数据组件 InputFormat (默认 TextInputFormat )会通过 getSplits 方法对输入目录中文件进行逻辑切片规划得到splits ,有多少个 split 就对应启动多少个 MapTask split block 的对应关 系默认是一对一。
2. 将输入文件切分为 splits 之后,由 RecordReader 对象(默认 LineRecordReader )进行读取,以 \n 作为分隔符,读取一行数据,返回 value> Key 表示每行首字符偏移值, value 表示这一行 文本内容。
3. 读取 split 返回 ,进入用户自己继承的 Mapper 类中,执行用户重写的 map 函数。 RecordReader读取一行这里调用一次。
4. map 逻辑完之后,将 map 的每条结果通过 context.write 进行 collect 数据收集。在 collect 中,会先对其进行分区处理,默认使用HashPartitioner
MapReduce 提供 Partitioner 接口,它的作用就是根据 key value reduce 的数量来决定当前的这对 输出数据最终应该交由哪个 reduce task 处理。默认对 key hash 后再以 reduce task 数量取模。默认的 取模方式只是为了平均 reduce 的处理能力,如果用户自己对 Partitioner 有需求,可以订制并设置到 job 上。
5. 接下来,会将数据写入内存,内存中这片区域叫做环形缓冲区,缓冲区的作用是批量收集 map 结 果,减少磁盘IO 的影响。我们的 key/value 对以及 Partition 的结果都会被写入缓冲区。当然写入之 前,key value值都会被序列化成字节数组。
      
环形缓冲区其实是一个数组,数组中存放着 key value 的序列化数据和 key value 的元数据信 息,包括 partition key 的起始位置、 value 的起始位置以及 value 的长度。环形结构是一个抽象概 念。
     缓冲区是有大小限制,默认是 100MB 。当 map task 的输出结果很多时,就可能会撑爆内存,所以需要在一定条件下将缓冲区中的数据临时写入磁盘,然后重新利用这块缓冲区。这个从内存往磁盘写数据的过程被称为Spill ,中文可译为溢写。这个溢写是由单独线程来完成,不影响往缓冲区写map结果的线程。溢写线程启动时不应该阻止 map 的结果输出,所以整个缓冲区有个溢写的比例 spill.percent。这个比例默认是 0.8 ,也就是当缓冲区的数据已经达到阈值( buffer size * spillpercent = 100MB * 0.8 = 80MB),溢写线程启动,锁定这 80MB 的内存,执行溢写过程。 Map task的输出结果还可以往剩下的 20MB 内存中写,互不影响
6. 当溢写线程启动后,需要对这 80MB 空间内的 key 做排序 (Sort) 。排序是 MapReduce 模型默认的行为 !
      如果job 设置过 Combiner ,那么现在就是使用 Combiner 的时候了。将有相同 key key/value 对的 value加起来,减少溢写到磁盘的数据量。 Combiner 会优化 MapReduce 的中间结果,所以它在整 个模型中会多次使用。
      那哪些场景才能使用 Combiner 呢?从这里分析, Combiner 的输出是 Reducer 的输入, Combiner绝不能改变最终的计算结果。Combiner 只应该用于那种 Reduce 的输入 key/value 与输出 key/value 类型完全一致,且不影响最终结果的场景。比如累加,最大值等。Combiner 的使用一定得慎重, 如果用好,它对job 执行效率有帮助,反之会影响 reduce 的最终结果。
7. 合并溢写文件:每次溢写会在磁盘上生成一个临时文件(写之前判断是否有 combiner ),如果map的输出结果真的很大,有多次这样的溢写发生,磁盘上相应的就会有多个临时文件存在。当整个数据处理结束之后开始对磁盘中的临时文件进行merge 合并,因为最终的文件只有一个,写入磁盘,并且为这个文件提供了一个索引文件,以记录每个reduce 对应数据的偏移量。
 
3. MapTask的并行度
MR 笔记二_第2张图片
4. ReduceTask 工作机制
MR 笔记二_第3张图片
Reduce 大致分为 copy sort reduce 三个阶段,重点在前两个阶段。 copy 阶段包含一个eventFetcher来获取已完成的 map 列表,由 Fetcher 线程去 copy 数据,在此过程中会启动两个 merge 线程,分别为inMemoryMerger onDiskMerger ,分别将内存中的数据 merge 到磁盘和将磁盘中的数据进行merge 。待数据 copy 完成之后, copy 阶段就完成了,开始进行 sort 阶段, sort 阶段主要是执行finalMerge操作,纯粹的 sort 阶段,完成之后就是 reduce 阶段,调用用户定义的 reduce 函数进行处理。
详细步骤
1. Copy 阶段,简单地拉取数据。 Reduce 进程启动一些数据 copy 线程 (Fetcher) ,通过 HTTP 方式请求 maptask获取属于自己的文件。
2. Merge 阶段。这里的 merge map 端的 merge 动作,只是数组中存放的是不同 map copy 来的数值。Copy 过来的数据会先放入内存缓冲区中,这里的缓冲区大小要比 map 端的更为灵活。 merge有三种形式:内存到内存;内存到磁盘;磁盘到磁盘。默认情况下第一种形式不启用。当内存中的数据量到达一定阈值,就启动内存到磁盘的merge 与map端类似,这也是溢写的过程,这个过程中如果你设置有Combiner ,也是会启用的,然后在磁盘中生成了众多的溢写文件。第二种merge方式一直在运行,直到没有 map 端的数据时才结束,然后启动第三种磁盘到磁盘的 merge方式生成最终的文件。
3. 合并排序。把分散的数据合并成一个大的数据后,还会再对合并后的数据排序。
4. 对排序后的键值对调用 reduce 方法,键相等的键值对调用一次 reduce 方法,每次调用会产生零个 或者多个键值对,最后把这些输出的键值对写入到HDFS 文件中.
 
5.ReduceTask并行度
ReduceTask 的并行度同样影响整个 Job 的执行并发度和执行效率,但与 MapTask 的并发数由切片数决定不同,ReduceTask数量的决定是可以直接手动设置 job . setNumReduceTasks ( 4 );
注意事项
1. ReduceTask=0 ,表示没有 Reduce 阶段,输出文件数和 MapTask 数量保持一致;
2. ReduceTask 数量不设置默认就是一个,输出文件数量为 1 个;
3. 如果数据分布不均匀,可能在 Reduce 阶段产生倾斜;

 

你可能感兴趣的:(MR)