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

Hadoop Reduce Copier详解:Map输出复制器与任务管理
深入解析Hadoop Reduce Copier的运作机制,包括Map输出复制器ReduceCopier的四大组件及其工作流程。重点讨论Map任务事件获取线程如何更新任务管理器,以及合并线程如何在内存或磁盘中合并Map输出。同时解释复制线程如何通过HTTP协议从TaskTracker获取Map任务输出,并讨论任务管理器如何调度、管理Map输出复制任务。
     在前面介绍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


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


### Map任务Reduce任务的概念 在分布式计算框架中,Map任务Reduce任务是核心组件之一。这些概念源自函数式编程领域,在Hadoop和其他类似的框架中得到了广泛应用。 #### Map任务工作原理 Map任务负责处理输入数据并将其转换成键值对的形式。具体来说: - 输入的数据被分割成多个分片(split),每个分片由一个单独的Mapper实例来处理。 - Mapper读取分片中的记录,并通过用户定义的映射逻辑将每条记录转化为若干个`<key,value>`形式的中间结果[^2]。 例如,在单词计数的例子中,对于每一行文本作为输入,map操作会输出形如`(word, 1)`这样的键值对集合。 ```java public class TokenizerMapper extends Mapper<Object, Text, Text, IntWritable> { private final static IntWritable one = new IntWritable(1); private Text word = new Text(); public void map(Object key, Text value, Context context) throws IOException, InterruptedException { StringTokenizer itr = new StringTokenizer(value.toString()); while (itr.hasMoreTokens()) { word.set(itr.nextToken()); context.write(word, one); // 输出(key-value): ("hello", 1), ("world", 1) } } } ``` #### Reduce任务工作原理 完成映射阶段之后,所有的中间键值对会被收集起来并通过网络传输给Reducer节点。Reducer的任务是对具有相同键的所有值执行聚合运算或其他类型的汇总操作。 - 来自不同Mapper产生的相同Key对应的Value列表会被发送到同一个Reducer上进行进一步加工。 - Reducer接收来自各个Mapper传来的数据流,按照相同的Key组合在一起形成新的键值对集合作为最终输出的一部分。 继续上面提到的词频统计案例,reduce过程会对所有带有特定词语作为Key的数值求和得到该词在整个文档集中出现次数的结果。 ```java public class IntSumReducer extends Reducer<Text,IntWritable,Text,IntWritable> { private IntWritable result = new IntWritable(); @Override protected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException { int sum = 0; for (IntWritable val : values) { sum += val.get(); // 对于("hello",[1,1]) -> 计算总和=2 } result.set(sum); context.write(key, result); // 输出(hello, 2) } } ``` ### 应用场景 MapReduce非常适合用于大规模数据分析任务,特别是当涉及到大量结构化或半结构化的离线批处理作业时表现尤为出色。典型的应用包括但不限于: - **日志分析**:解析Web服务器的日志文件以提取访问模式、错误报告等有用信息; - **搜索引擎索引构建**:从网页抓取的内容创建倒排索引来加速查询响应时间; - **机器学习模型训练**:利用海量样本数据来进行参数估计与优化算法迭代更新;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值