Reduce任务的Map输出复制器—ReduceCopier

来源:互联网 发布:普开数据骗局 编辑:程序博客网 时间:2024/06/04 00:27
在前面介绍Hadoop的Reduce任务执行框架的时候说过,作业的每一个Map任务被执行完之后,它们的输出结果均保存在各自执行节点的本地磁盘上,当reduce任务执行的时候,它需要自己去到所有的Map节点上取回属于自己的map输出,直到属于自己的所有map输出copy到本地,reduce任务才开始接下来的工作。那么,Reduce是如何从Map节点取回自己的输入数据呢?这就是本文即将要详细讲述的内容——Map输出复制器ReduceCopier。

     Map输出复制器ReduceCopier主要有四大组件:复制线程(MapOutputCopier)、合并线程(本地文件合并线程LocalFSMerger、内存合并线程InMemFSMergeThread)、Map任务事件获取线程、任务管理器。复制线程就是通过http协议从成功执行了某一map任务的TaskTracker上获取该map任务的输出结果(属于自己的);合并线程就是将所有的属于自己的map输出合并成一个输出结合作为自己的reduce操作输入;Map任务事件获取线程不断地从负责执行该Reduce任务的TaskTracker上获取已经完成或者已经放弃的map任务,然后将这些map任务添加/更新到复制任务管理器;任务管理器负责管理已经完成的map输出复制任务、正在执行的map输出复制任务、待调度的map输出复制任务、放弃的map输出复制任务等。下面先来整体的看看这些工作组件是如何来统一工作的吧!


        

      从上面的结构框架图中,我们可以发现Map输出复制器ReduceCopier中所有线程(复制线程、合并线程)的任务均来自Map任务事件获取线程,所以在接下来的讨论中,我将首先从Map任务事件获取线程讲起。

1.Map任务事件获取线程

   MapEventGetThread线程每隔一段时间(目前hadoop-0.2.0版本是1000ms)就会就会从它的TaskTracker上获取一批当前作业的map任务事件,利用这些map任务事件来更新任务管理器,具体的过程如下:



2.任务管理器

    这里的任务管理器(TaskManager)在ReduceMap中没有任何描述,只是我从中抽象出来的一个概念,它一方面管理各种任务队列及相关集合,另一方也负责调度任务。它所管理的任务队列包括:

Set<TaskID>  copiedMapOutputs  //保存已经成功完成复制map输出的对应Map任务

List<MapOutputLocation> retryFetches  //保存复制失败有可再试的Map实例任务

Map<String,List<MapOutputLocation>>  mapLocaltions  //按照复制任务所在的主机划分任务

List<MapOutputLocation> scheduledCopies  //将要被执行的任务

Set<String> uniqueHosts  //正在执行复制任务的主机

Map<String,Long> penaltyBox  //正在受惩的主机

Set<TaskAttemptID> obsoleteMapIds  //不需要执行复制的Map实例任务

Set<TaskID> fetchFailedMaps  //复制失败的Map任务

Map<TaskAttemptID,Integer> mapTaskToFailedFetchesMap  //复制Map实例任务输出失败的次数

那么,他有事如何调度的呢?其实,这个过程还是比较的复杂的。


这里要补充上面的处理过程中两个相关的参数:复制任务的最大失败次数(可重试次数)maxFetchRetriesPerMap和最大失败任务数maxFailedUniqueFetches。它们是这样取值的:

int maxBackoff = conf.getInt("mapred.reduce.copy.backoff", 300);
final int BACKOFF_INIT = 4000; 
final int MIN_FETCH_RETRIES_PER_MAP = 2;
int maxFailedUniqueFetches = 5;

maxFetchRetriesPerMap = Math.max(MIN_FETCH_RETRIES_PER_MAP, getClosestPowerOf2((maxBackoff * 1000 / BACKOFF_INIT) + 1));
maxFailedUniqueFetches = Math.min(numMaps, maxFailedUniqueFetches);

奇怪的是这俩参数是个啥意思呢?也就是当一个复制任务的失败次数达到maxFetchRetriesPerMap时,就认为这个任务是个失败的任务(造成复制失败的原因可能是该任务对应的节点失败了,或者该节点对应的网络阻塞了等),当失败的任务数达到时,该Reduce实例任务就认为自己已经不可能完成再成功完成任务了,然后通知它对应的TaskTracker来kill掉自己,所以在这种情况下,我们经常会看到这样的警告:

Shuffle failed with too many fetch failures and insufficient progress! Killing task attempt_201112221359_0001_r_******.

3.合并线程

    这里的合并线程分为两种,一种是在内部不足的情况下利用磁盘作为中转来合并map任务的输出,另一种是在内部充足的情况下直接在内存中合并map任务的输出,它们的流程很简单:

其中,参数ioSortFactor的取值为配置文件mapred-*.xml中的io.sort.factor项。

4.复制线程(MapOutputCopier)

    Map输出复制器ReduceCopier在其内部采用多线程的方式来从其它的TaskTracker上通过http协议请求的复制属于自己的Map任务输出结果。至于复制线程的个数可在配置文件mapred-site.xml中配置,对应的配置项:mapred.reduce.parallel.copies,为了提高reduce及整个Hadoop的效率,这个值应该设置和该作业的Map任务数差不多。每一个复制线程都从scheduledCopies 中获取一个任务来执行,在接受目标TaskTracker传过来的Map输出数据时,它会根据当前内存情况决定将该数据存放在村内还是磁盘。在Hadoop-0.2.0版本中,一个复制Map输出的http请求的URL如下:

http://*.*.*.*:50060/mapOutput?job=job_*_*&map=attempt_*_*_m_*_*&reduce=0


    关于复制线程的详细过程在这里就不在详述了。