MapTask的RecordWriter实现之NewOutputCollector

在前面的一系列文章中我不断的提到了记录写入器RecordWriter<K,V>,它是一个抽象类,在map任务执行中的根本作用就是向某个文件系统的文件中写入map任务的输出结果——key-value集。所以,本文将主要讨论MapTask对记录写入器RecordWriter<K,V>的一个具体实现类——NewOutputCollector,来好好的看看这个NewOutputCollector对map任务的输出key-value集合做了哪些事情,最后又是如何以何种方式存入某个文件系统的

相关阅读:

NewOutputCollector的类名我们就可以大致的知道这个类的用户,即map任务的输出结果收集器。还是先来了解一下与它相关的类吧!

MapTask的RecordWriter实现之NewOutputCollector


这里的NewOutputCollector实际上可以看作是直接接受来自map操作输出的key-value,而NewOutputCollector的write实现也很简单,它什么也没有做,而是直接将这个key-value交给了MapOutputCollector的实现MapOutputBuffer

来做。可以简单的看一下的write(K,V)实现

public void write(K key, V value) throws IOException, InterruptedException {
      collector.collect(key, value, partitioner.getPartition(key, value, partitions));
 }

哦,对了,这里还要稍微的提一下map输出分配器partitioner,它主要是用来决定对于map操作的一个输出应该交给那个reduce来处理。

     下面就要好好的来看看map输出收集器MapOutputCollector的重量级实现MapOutputBuffer。这个map输出收集器的作用就是按照一个map输出(key-value)应该交由哪个reduce处理来收集map的结果输出,最终被分配给相同的reduce任务的map输出被存放到同一个文件或是某一个文件中的连续区域。当然,这中间可能还存在key-value的排序操作。那么,可能有不少人想要问,对map的输出进行分类、排序,可能会占用大量的系统内存,MapOutputBuffer又是如何解决这个问题的呢?MapOutputBuffer在其内部采用了先分后合的策略来对map的大量输出进行分类和排序的,为了提高效率,这中间就少不了使用一定的缓存了。那么MapOutputBuffer是如何充分利用缓存的呢?接下来就要请大家注意了,因为我将介绍的有关内容会涉及到mapreduce的调优问题了。浏览一下与MapOutputBuffer缓存有关的内部属性:

MapTask的RecordWriter实现之NewOutputCollector


MapOutputBuffer内部大缓存大小可以由用户在配置文件中设置,这个设置对应文件maprd-site.xml中的io.sort.mb项,值得单位是MB。MapOutputBuffer将这个缓存分为了二部分,第一部分用来存放key-value的二进制具体值,对应的属性kvbuffer,第二部分用来指定一个key-value属于哪个reduce、它们的key、value值分别在kvbuffer中的偏移位置,对应的属性为kvoffsetskvindices,它们的物理布局可以这样来表示:

MapTask的RecordWriter实现之NewOutputCollector


那么,如何分配kvbuffer和(kvoffsets+kvindices)的大小将影响到缓存的使用效率,这个机器永远也无法知道,所以缓存的分配就需要用户根据实际的作业来估算它们大约分别占缓存的多少,这个百分比可以通过配置文件mapred-site.xml的io.sort.record.percent项来配置,同时这个值在Hadoop的0.2.2版本中不能超过1.0也不能小于0.01,这个分配过程具体如下:

MapTask的RecordWriter实现之NewOutputCollector

另外,为了提高map输出处理的整体效率,MapOutputBuffer为缓存设置了一个阈值softRecordLimit,当缓存的key-value数量超过这个值得时候,就要通知溢出处理线程spillThread开始处理已经缓存的key-value,处理完之后,它们会被保存到一个临时的本地文件中(最后会合并它们),同时释放它们占用的缓存。在这个过程中,MapOutputBuffer剩余的缓存任然可以接受map的输出key-value,在效率方面你懂的!MapOutputBuffer的缓存使用阈值可以通过配置文件mapred-site.xml的io.sort.spill.percent项来配置,这个值表示占总缓存的百分比,最后的计算结果也很简单:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/pszgp.html