MapReduce深度分析(一)

一、数据流向分析

  图为MapReduce数据流向示意图

  步骤1、输入文件从HDFS流向到Mapper节点。在一般情况下,存储数据的节点就是Mapper运行的节点,不需要在节点之间进行数据传输,也就是尽量让存储靠近计算。

  步骤2、mapper输出到内存缓冲区。Mapper的输入是解析后的键值对,输出是经过处理后新的<key,value>键值对。mapper的输出并不是直接写到本地文件系统,而是先写入一个内存缓冲区,当缓冲区达到一定的阈值后就将缓冲区中的数据以一个临时文件的形式写入本地磁盘。partitioner就是发生在这个阶段,也就是在写入内存缓冲区的同时执行了partitioner对文件进行分区,以便后续对Reduce进行处理。

  步骤3、从内存缓冲区到磁盘。当缓冲区达到100M,溢写比例默认是0.8。从缓冲区写到本地磁盘的过程就是spill。溢写线程启动同时会对这80M的内存数据依据key进行排序,如果用户作业设置了Combiner,那么在写到磁盘之前,会对Map输出的键值对调用Combiner类做规约操作。目的是减少溢写到本地磁盘文件的数据量。这个过程还涉及对多次临时文件的合并,排序后最终形成Region文件。

  步骤4、从Mapper端的本地文件系统流向Reduce端。也就是Shuffle阶段。复制数据阶段。

  步骤5、从Reduce端内存缓冲区流向Reduce端的本地磁盘。这个过程就是Reduce中的Merge和Sort阶段。Merge分为三种情况,内存文件合并,磁盘文件合并,同时还会以key为键进行排序,最终会生成已经对相同key的value进行聚集并排序号的输出文件。

  步骤6、Merge和Sort之后直接流向Reduce函数进行规约操作。

  步骤7、Reduce处理完毕之后根据用户指定的输出类型写入HDFS中,生成相应的part-*形式的输出文件。

二、处理流程分析

  

  步骤1、用户的应用通过JobClient类提交到JobTracker,在JobClient类中,将用户程序的Mapper类,Reducer类以及配置JobConf打包成一个JAR文件并保存在HDFS中,需要指定JobConf的输入路径(a)、输出路径,Mapper和Reducer类名的参数。JobClient在提交作业的时候,将作业jar文件的路径一起提交到JobTracker的master服务,也就是作业调度器。见序号1

  步骤2、在JobClient提交Job后,JobTracker会创建一个JobInProgress来跟踪和调度这个作业,并将其添加到调度器的作业队列中,见序号2

  步骤3、JobInProgress会根据提交作业jar文件中定义的输入数据集创建相应数量的TaskInProcess用于监控和调度MapTask和ReduceTask,序号3

  步骤4、JobTracker启动任务时通过TaskInProgress来启动作业任务序号4,这时会把Task对象(MapTask和ReduceTask)序列化写入相应的TaskTracker服务中。序号5

  步骤5、TaskTracker收到后创建相应的TaskInProgress用于监控和调度运行该Task,序号6

  步骤6、启动具体的Task进程,TaskTracker通过TaskInProgress管理的TaskRunner对象运行具体的Task,序号7

  步骤7、TaskRunner自动装载作业jar文件,并设置好环境变量后启动一个独立的Java子进程来执行Task,TaskRunner会首先调用执行MapTask,序号8

  步骤8、MapTask先调用Mapper,进行Mapper的相关操作。

  步骤9、MapTask的任务完成之后,TaskRunner调用ReduceTask进程来启动Reducer,需要注意的是MapTask和ReduceTask不一定会运行在同一个TaskTracker中。

  步骤10、ReduceTask直接调用Reducer类处理Mapper的输出结果,Reducer生成最终的结果键值对,写到HDFS中。

三、MapTask实现分析

  MapTask先被TaskRunner调用执行,然后调用执行用户的Mapper类从而开始Map任务处理阶段,因此MapTask是整个Map阶段最核心的类。

  图为MapTask总执行逻辑图。通过调用initialize()方法执行初始化工作。Map的初始化任务包括JobContext、TaskContext、输出路径等,调用Task.initialize()方法。初始化完成之后会依次判断作业类型,MapTask中三种特殊的作业:cleanupJobTask(清理Map任务)、setupJobTask(初始化Map任务)和TaskCleanupTask(清理作业任务),这三种类型的作业会根据需要进行判断调用。

  处理流程:

    步骤1、创建执行Mapper所需要的对象。首先创建的对象有:TaskAttemptContext、Mapper、InputFormat、InputSplit、RecordReader。这些类的对象主要为Mapper要读取的输入数据及切分准备。

    步骤2、创建所需要的输出收集器OutputCollector。

    步骤3、初始化RecordReader,通过input.initialize(split,mapperContext)来对输入数据进行初始化。

    步骤4、执行Mapper,通过mapper.run(mapperContext)最终调用用户指定的Mapper类对数据进行Map操作。

  以上就是RunNewMapper总的处理步骤。

  对于以上步骤可以分为以下几个阶段:

    Read阶段:通过RecordReader对象,对HDFS上的文件进行split切分,调用用户指定的输入文件格式类解析每一个split文件,输出<key,value>键值对。

    Map阶段:对输入的键值对调用用户编写的Map函数进行处理,并输出<key,value>键值对

    Collector和Partitioner阶段:收集Mapper的输出,并在OutputCollector函数内部对键值对进行Partitioner分区,以便确定相应的Reducer处理,这个阶段将最终的键值对集合输出到内存缓冲区。

    Spill阶段:包含Sort和Combiner阶段,从内存缓冲区写到磁盘的过程。

    Merge阶段:对Spill阶段在本地磁盘生成的小文件进行多次合并,生成一个大文件。

  下面具体分析每个阶段的具体任务:

    Read阶段:首先通过taskContext.getInputFormatClass()得到用户指定的InputFormatClass来创建InputFormat对象实例;其次创建InputSplit对象,这个对象负责对文件进行数据块的逻辑切分;最后,创建RecordReader对象。InputFormat对象会提供getSplit()重要方法,通过getSplit将输入文件切分成多个逻辑InputSplit实例并返回,每一个InputSplit实例就由对应的一个Mapper处理,通过RecordReader对象把InputSplit提供的输入文件转化为Mapper所需要的keys/values键值对集合。

    Map阶段:Mapper类中有setup、map、cleanup、run四个核心方法,通过调用run方法,依次执行setup(context)-->map()-->cleanup(context)

    Collector和Partitioner阶段:map函数处理的结果不直接写到内存缓冲区,而有一个Collector对象进行收集。partition是对应的Reduce分区号,是Partitioner的返回值,也就是传到Reduce节点处理。自定义的MapperOutputCollector接口,并实现collect、close、flush方法。

    Spill阶段:首先创建spill文件,2、按照partition的顺序对内存缓冲区中的数据进行排序。3、循环依次将每个partition写入磁盘文件。4、创建spill index文件。

    Merge阶段:经过spill阶段会生成多个spill.out文件和相应的索引文件spill.out.index,MapTask最终需要将这些形式的临时文件经过多次合并成一个大的输出文件。

四、ReduceTask实现分析

  和MapTask类似,ReduceTask也继承了Task类,重写了run方法,ReduceTask就是调用run方法来执行Reduce任务的。

  图为ReduceTask整体的处理逻辑,首先是ReduceTask的初始化工作,包括添加Reduce过程需要经过的copy、sort和Reduce阶段,以便通知JobTracker目前运行的情况,设置并启动reporter进程以便和JobTracker进行交流,最后进行一些和任务输出相关的设置。比如创建commiter,设置工作目录等。ReduceTask阶段分为四个阶段:

  shuffle阶段:这个阶段就是Reduce中的copy阶段,运行Reduce的TaskTracker需要从各个Mapper节点远程复制属于自己处理的一段数据。

  Merge阶段:进行多次合并。

  sort阶段:虽然每个Mapper的输出是按照key排序好的,但是经过Shuffle和Merge阶段后并不是统一有序的。

  Reduce阶段:在Sort阶段完成后,执行Reduce类进行规约。

MapReduce深度分析(一)的更多相关文章

  1. MapReduce深度分析(二)

    MapReduce深度分析(二) 五.JobTracker分析 JobTracker是hadoop的重要的后台守护进程之一,主要的功能是管理任务调度.管理TaskTracker.监控作业执行.运行作业 ...

  2. 深度分析如何在Hadoop中控制Map的数量

    深度分析如何在Hadoop中控制Map的数量 guibin.beijing@gmail.com 很多文档中描述,Mapper的数量在默认情况下不可直接控制干预,因为Mapper的数量由输入的大小和个数 ...

  3. const与readonly深度分析(.NET)

    前言 很多.NET的初学者对const和readonly的使用很模糊,本文就const和readonly做一下深度分析,包括: 1. const数据类型的优势 2. const数据类型的劣势 3. r ...

  4. 转:[gevent源码分析] 深度分析gevent运行流程

    [gevent源码分析] 深度分析gevent运行流程 http://blog.csdn.net/yueguanghaidao/article/details/24281751 一直对gevent运行 ...

  5. 深度分析 Java 的枚举类型:枚举的线程安全性及序列化问题(转)

    写在前面: Java SE5 提供了一种新的类型 Java的枚举类型,关键字 enum 可以将一组具名的值的有限集合创建为一种新的类型,而这些具名的值可以作为常规的程序组件使用,这是一种非常有用的功能 ...

  6. AndroidService 深度分析(2)

    AndroidService 深度分析(2) 上一篇文章我们Service的生命周期进行了測试及总结. 这篇文章我们介绍下绑定执行的Service的实现. 绑定执行的Service可能是仅为本应用提供 ...

  7. MapReduce源代码分析MapTask分析

    前言 MapReduce该分析是基于源代码Hadoop1.2.1代码分析进行的基础上. 该章节会分析在MapTask端的详细处理流程以及MapOutputCollector是怎样处理map之后的col ...

  8. 【JVM】深度分析Java的ClassLoader机制(源码级别)

    原文:深度分析Java的ClassLoader机制(源码级别) 为了更好的理解类的加载机制,我们来深入研究一下ClassLoader和他的loadClass()方法. 源码分析 public abst ...

  9. 深度分析Java的枚举类型—-枚举的线程安全性及序列化问题

    原文:深度分析Java的枚举类型--枚举的线程安全性及序列化问题 枚举是如何保证线程安全的 要想看源码,首先得有一个类吧,那么枚举类型到底是什么类呢?是enum吗?答案很明显不是,enum就和clas ...

随机推荐

  1. PAT1011

    With the 2010 FIFA World Cup running, 随着2010世界杯的举行 football fans the world over were becoming increa ...

  2. 深入理解setTimeout和setinterval

    以前一直以为这两个函数就是简单了认为类似thread一样的东西, 认为会在一个时间片内, 并发的执行调用的函数, 似乎很好很强大, 但其实并不是如此, 实际的情况是javascript都是以单线程的方 ...

  3. Cordova插件开发

    我在网上找了很多关于Cordova插件开发的例子,都不是我想要的,我只想要,怎么调用这个生成出来的js,最终得到了最为直接又简单的方法,希望给能帮助到大家! document.addEventList ...

  4. Windows Server 2012 在个人终端上使用的推荐设置

    Windows Server 2012,也就是 Windows 8 的服务器版本,相对于 Windows 8 企业版而言,增强了作为服务器的功能,弱化了作为终端系统的功能. 目前微软官方提供了 Win ...

  5. H2最完整的资料下载地址:

    淡泊以明志,宁静以致远 博客园 首页 新随笔 联系 管理 订阅 随笔- 678  文章- 0  评论- 137  H2 database的使用   H2最完整的资料下载地址: http://downl ...

  6. 注解用法详解——@SuppressWarnings

    一.前言 编码时我们总会发现如下变量未被使用的警告提示: 上述代码编译通过且可以运行,但每行前面的“感叹号”就严重阻碍了我们判断该行是否设置的断点了.这时我们可以在方法前添加 @SuppressWar ...

  7. Jsoup使用教程

    一.解析和遍历一个HTML文档1.解析Html及Url链接 String html = "<html><head><title>First parse&l ...

  8. POJ3255次短路

    POJ3255 题意:给定一个图,求从1到n的次短路 分析:我们需要在dijkstra上作出一些修改,首先,到某个顶点v的次短路要么是到其他某个顶点u的最短路在加上u到v的边,要么是到v的次短路再加上 ...

  9. 【亲测】Python:解决方案:Python Version 2.7 required, which was not found in the registry

    好久不更新随笔了,今天因为数据可视化作业,想抓取一些人人网好友关系数据,于是开始尝试python,用到numpy模块,安装的时候提示: 'Python Version 2.7 required, wh ...

  10. Crazyflie笔记五: CRTP 实时通信协议(一)(转)

    源:Crazyflie笔记五: CRTP 实时通信协议(一) 这里详细介绍了 Crazyflie 的 CRTP实时通信协议的相关内容,由于内容很长,分几篇博文来讲述.这里是第一节内容.欢迎交流:301 ...