Hadoop MapReduce之ReduceTask任务执行(三)

原创 2013年12月02日 14:23:49
在reduce端的文件拷贝阶段,会将数据放入内存或直接放入磁盘中,如果文件全部拷贝完再进行合并那样必然降低作业效率,所以在拷贝进行到一定阶段,数据的合并就开始了,负责该工作的有两个线程:InMemFSMergeThread和LocalFSMerger,分别针对内存和磁盘Segment的合并。
首先看内存合并线程InMemFSMergeThread的run函数
  public void run() {
    LOG.info(reduceTask.getTaskID() + " Thread started: " + getName());
    try {
      boolean exit = false;
      do {
        exit = ramManager.waitForDataToMerge(); //检测是否需要合并
        if (!exit) {
          doInMemMerge();//执行合并
        }
      } while (!exit);
    } catch (Exception e) {
      LOG.warn(reduceTask.getTaskID() +
               " Merge of the inmemory files threw an exception: "
               + StringUtils.stringifyException(e));
      ReduceCopier.this.mergeThrowable = e;
    } catch (Throwable t) {
      String msg = getTaskID() + " : Failed to merge in memory" 
                   + StringUtils.stringifyException(t);
      reportFatalError(getTaskID(), t, msg);
    }
  }
  下面是内存合并的条件,注释写的已经很清楚了,这里需要注意的是内存的使用量、拷贝完毕的文件数、挂起线程数,线程挂起的判断条件是用于保留map端数据的内存超过阈值,可参考ShuffleRamManager.reserve()函数
  public boolean waitForDataToMerge() throws InterruptedException {
    boolean done = false;
    synchronized (dataAvailable) {
             // Start in-memory merge if manager has been closed or...
      while (!closed
             &&
             // In-memory threshold exceeded and at least two segments
             // have been fetched
             (getPercentUsed() < maxInMemCopyPer || numClosed < 2)
             &&
             // More than "mapred.inmem.merge.threshold" map outputs
             // have been fetched into memory
             (maxInMemOutputs <= 0 || numClosed < maxInMemOutputs)
             && 
             // More than MAX... threads are blocked on the RamManager
             // or the blocked threads are the last map outputs to be
             // fetched. If numRequiredMapOutputs is zero, either
             // setNumCopiedMapOutputs has not been called (no map ouputs
             // have been fetched, so there is nothing to merge) or the
             // last map outputs being transferred without
             // contention, so a merge would be premature.
             (numPendingRequests < 
                  numCopiers*MAX_STALLED_SHUFFLE_THREADS_FRACTION && 
              (0 == numRequiredMapOutputs ||
               numPendingRequests < numRequiredMapOutputs))) {
        dataAvailable.wait();
      }
      done = closed;
    }
    return done;
  }  
  这里的合并可以和map端的合并对比来看,逻辑大同小异,确定文件名、构建写入器,将segment放入合并队列中,如果有本地合并函数则先合并否则直接写入文件。
  private void doInMemMerge() throws IOException{
    if (mapOutputsFilesInMemory.size() == 0) {
      return;
    }
    
    //name this output file same as the name of the first file that is 
    //there in the current list of inmem files (this is guaranteed to
    //be absent on the disk currently. So we don't overwrite a prev. 
    //created spill). Also we need to create the output file now since
    //it is not guaranteed that this file will be present after merge
    //is called (we delete empty files as soon as we see them
    //in the merge method)


    //figure out the mapId 
    TaskID mapId = mapOutputsFilesInMemory.get(0).mapId;


    List<Segment<K, V>> inMemorySegments = new ArrayList<Segment<K,V>>();
    long mergeOutputSize = createInMemorySegments(inMemorySegments, 0);
    int noInMemorySegments = inMemorySegments.size();


    Path outputPath =
        mapOutputFile.getInputFileForWrite(mapId, mergeOutputSize);


    Writer writer = 
      new Writer(conf, rfs, outputPath,
                 conf.getMapOutputKeyClass(),
                 conf.getMapOutputValueClass(),
                 codec, null);


    RawKeyValueIterator rIter = null;
    try {
      LOG.info("Initiating in-memory merge with " + noInMemorySegments + 
               " segments...");
      
      rIter = Merger.merge(conf, rfs,
                           (Class<K>)conf.getMapOutputKeyClass(),
                           (Class<V>)conf.getMapOutputValueClass(),
                           inMemorySegments, inMemorySegments.size(),
                           new Path(reduceTask.getTaskID().toString()),
                           conf.getOutputKeyComparator(), reporter,
                           spilledRecordsCounter, null);
      
      if (combinerRunner == null) {
        Merger.writeFile(rIter, writer, reporter, conf);
      } else {
        combineCollector.setWriter(writer);
        combinerRunner.combine(rIter, combineCollector);
      }
      writer.close();


      LOG.info(reduceTask.getTaskID() + 
          " Merge of the " + noInMemorySegments +
          " files in-memory complete." +
          " Local file is " + outputPath + " of size " + 
          localFileSys.getFileStatus(outputPath).getLen());
    } catch (Exception e) { 
      //make sure that we delete the ondisk file that we created 
      //earlier when we invoked cloneFileAttributes
      localFileSys.delete(outputPath, true);
      throw (IOException)new IOException
              ("Intermediate merge failed").initCause(e);
    }


    // Note the output of the merge
    FileStatus status = localFileSys.getFileStatus(outputPath);
    synchronized (mapOutputFilesOnDisk) {
      addToMapOutputFilesOnDisk(status);
    }
  }
}
磁盘文件的合并与此大致相同,可以具体细节可以查看org.apache.hadoop.mapred.ReduceTask.ReduceCopier.LocalFSMerger

相关文章推荐

Hadoop MapReduce之ReduceTask任务执行(五)

本节分析ReduceTask的最后一个阶段:reduce,经历了copy、sort后,reduce的输入数据就准备好了,reduce数据输入由Reducer.Context提供,该Context封装了...
  • lihm0_1
  • lihm0_1
  • 2013年12月05日 15:30
  • 1500

Hadoop MapReduce之ReduceTask任务执行(四):排序与合并

上一篇讲了reduce如何把map输出下载到本地的过程,这个过程中包含了文件合并操作,本文主要讲reduce的下一个阶段:排序。reduce端的合并单位是Segment,在对Segment合并的过程中...

hadoop-mapreduce中reducetask运行分析

ReduceTask的运行 Reduce处理程序中需要执行三个类型的处理, 1.copy,从各map中copy数据过来 2.sort,对数据进行排序操作。 3.reduce,执行业务逻辑的处理...

Hadoop MapReduce之MapTask任务执行(二)

(为了简单起见,我们这里分析官方文档中使用的WordCount程序)   上一篇我们已经看到自己的map函数是如何被调用的,这是一个循环调用的过程,这里我们分析下,从KV读入到KV写出的过程,通常我们...
  • lihm0_1
  • lihm0_1
  • 2013年11月14日 18:16
  • 1567

Hadoop MapReduce之MapTask任务执行(四)

Map任务执行完前会对spill文件进行合并操作,每次spill都会生成一个spill文件,在传向reduce前,map会把这些文件合并为一个文件,文件合并不是一次性把所有文件合并的,每次合并的个数可...
  • lihm0_1
  • lihm0_1
  • 2013年11月23日 14:27
  • 1271

Hadoop MapReduce 任务执行流程源代码详细解析

目录 1 引言  1.1 目的  1.2 读者范围 2 综述 3 代码详细分析  3.1 启动Hadoop集群  3.2 JobTracker启动以及Job的初始化  3.3 Task...
  • RiverM
  • RiverM
  • 2011年09月27日 15:01
  • 14283

hadoop执行mapreduce任务,能够map,不能reduce,Shuffle阶段报错

第一次运行: [root@sjfx jar]# hadoop jar /home/tangzw/jar/GameLoginLogAnalyzeA.jar /tangzw/input ...
  • tzw1992
  • tzw1992
  • 2014年05月15日 15:39
  • 2891

hadoop 里执行 MapReduce 任务的几种常见方式

说明: 测试文件: 1 echo -e "aa\tbb \tcc\nbb\tcc\tdd" > 3.txt ...
  • jeek566
  • jeek566
  • 2013年07月04日 10:48
  • 508

记Hadoop2.5.0线上mapreduce任务执行map任务划分的一次问题解决

近日在线上发现有些mapreduce作业的执行时间很长,我们需要解决这个问题。输入文件的大小是5G,采用了lzo压缩,整个集群的默认block大小是128M。本文将详细描述这次线上问题的排查过程。...
  • beliefer
  • beliefer
  • 2016年07月14日 13:31
  • 11079

MapTask并行度决定机制、FileInputFormat切片机制、map并行度的经验之谈、ReduceTask并行度的决定、MAPREDUCE程序运行演示(来自学笔记)

1.3 MapTask并行度决定机制maptask的并行度决定map阶段的任务处理并发度,进而影响到整个job的处理速度那么,mapTask并行实例是否越多越好呢?其并行度又是如何决定呢? 1.3.1...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Hadoop MapReduce之ReduceTask任务执行(三)
举报原因:
原因补充:

(最多只允许输入30个字)