有了上面Mapper输出的内存存储结构和硬盘存储结构讨论,我们来细致分析MapOutputBuffer的流程。首先是成员变量。最先初始化的是作业配置job和统计功能reporter。通过配置,MapOutputBuffer能够获取本地文件系统(localFs和rfs),Reducer的数目和Partitioner。

SpillRecord是文件spill.out{spill号}.index在内存中的相应抽象(内存数据和文件数据就差最后的校验和),该文件保持了一系列的IndexRecord,例如以下图:



 

IndexRecord有3个字段,各自是startOffset:记录偏移量。rawLength:初始长度,partLength:实际长度(可能有压缩)。

SpillRecord保持了一系列的IndexRecord,并提供方法用于加入记录(没有删除记录的操作,由于不须要)。获取记录,写文件,读文件(通过构造函数)。

接下来是一些和输出缓存区kvbuffer。缓存区记录索引kvindices和缓存区记录索引排序工作数组kvoffsets相关的处理,以下的图有助于说明这段代码。

 



这部分依赖于3个配置參数,io.sort.spill.percent是kvbuffer,kvindices和kvoffsets的总大小(以M为单位。缺省是100,就是100M,这一部分是MapOutputBuffer中占用存储最多的)。

io.sort.record.percent是kvindices和kvoffsets占用的空间比例(缺省是0.05)。

前面的分析我们已经知道kvindices和kvoffsets,假设记录数是N的话,它占用的空间是4N*4bytes,依据这个关系和io.sort.record.percent的值。我们能够计算出kvindices和kvoffsets最多能有多少个记录。并分配相应的空间。參数io.sort.spill.percent指示当输出缓冲区或kvindices和kvoffsets记录数量到达相应的占用率的时候。会启动spill,将内存缓冲区的记录存放到硬盘上。softBufferLimit和softRecordLimit为相应的字节数。

值对<key, value>输出到缓冲区是通过Serializer串行化的。这部分的初始化跟在上面输出缓存后面。接下来是一些计数器和可能的数据压缩处理器的初始化,可能的Combiner和combiner工作的一些配置。

最后是启动spillThread。该Thread会检查内存中的输出缓存区。在满足一定条件的时候将缓冲区中的内容spill到硬盘上。这是一个标准的生产者-消费者模型,MapTask的collect方法是生产者,spillThread是消费者,它们之间同步是通过spillLock(ReentrantLock)和spillLock上的两个条件变量(spillDone和spillReady)完毕的。

先看生产者。MapOutputBuffer.collect的主要流程是:

l           报告进度和參数检測(<K,V>符合Mapper的输出约定);

l           spillLock.lock(),进入临界区。

l           假设达到spill条件。设置变量并通过spillReady.signal(),通知spillThread;并等待spill结束(通过spillDone.await()等待);

l           spillLock.unlock();

l           输出key,value并更新kvindices和kvoffsets(注意,方法collect是synchronized,key和value各自输出。它们也会占用连续的输出缓冲区)。

kvstart,kvend和kvindex三个变量在推断是否须要spill和spill是否结束的过程中非常重要。kvstart是有效记录開始的下标。kvindex是下一个可做记录的位置。kvend的作用比較特殊,它在普通情况下kvstart==kvend。但開始spill的时候它会被赋值为kvindex的值,spill结束时。它的值会被赋给kvstart,这时候kvstart==kvend。

这就是说。假设kvstart不等于kvend,系统正在spill,否则。kvstart==kvend。系统处于普通工作状态。

事实上在代码中。我们能够看到非常多kvstart==kvend的推断。

以下我们分情况,讨论kvstart,kvend和kvindex的配合。初始化的时候。它们都被赋值0。



 



下图给出了一个没有spill的记录加入过程:



 



注意kvindex和kvnext的关系,取模实现了循环缓冲区

假设在加入记录的过程中,出现spill(多种条件),那么,基本的步骤例如以下:



 



首先还是计算kvnext。主要,这个时候kvend==kvstart(图中没有画出来)。

假设spill条件满足,那么,kvindex的值会赋给kvend(这是kvend不等于kvstart),从kvstart和kvend的大小关系,我们能够知道记录位于数组的那一部分(左边是kvstart<kvend的情况,右边是另外的情况)。Spill结束的时候,kvend值会被赋给kvstart,kvend==kvstart又又一次满足。同一时候。我们能够发现kvindex在这个过程中没有变化。新的记录还是写在kvindex指向的位置,然后,kvindex=kvnect,kvindex移到下一个可用位置。

大家体会一下上面的过程,特别是kvstart,kvend和kvindex的配合,事实上,<key。value>对输出使用的缓冲区,也有类似的过程。

Collect在处理<key。value>输出时。会处理一个MapBufferTooSmallException,这是value的串行化结果太大。不能一次放入缓冲区的指示,这样的情况下我们须要调用spillSingleRecord,特殊处理。

很多其它精彩内容请关注:http://bbs.superwu.cn

关注超人学院微信二维码:

关注超人学院java免费学习交流群:

Hadoop源码分析(MapTask辅助类,II)的更多相关文章

  1. Hadoop源码分析之数据节点的握手,注册,上报数据块和心跳

    转自:http://www.it165.net/admin/html/201402/2382.html 在上一篇文章Hadoop源码分析之DataNode的启动与停止中分析了DataNode节点的启动 ...

  2. Hadoop源码分析之Configuration

    转自:http://www.it165.net/admin/html/201312/2178.html org.apache.hadoop.conf.Configuration类是Hadoop所有功能 ...

  3. hadoop源码分析(2):Map-Reduce的过程解析

    一.客户端 Map-Reduce的过程首先是由客户端提交一个任务开始的. 提交任务主要是通过JobClient.runJob(JobConf)静态函数实现的: public static Runnin ...

  4. Hadoop源码分析之FileSystem抽象文件系统

    Hadopo提供了一个抽象的文件系统模型FileSystem,HDFS是其中的一个实现. FileSystem是Hadoop中所有文件系统的抽象父类,它定义了文件系统所具有的基本特征和基本操作. Fi ...

  5. Hadoop源码分析之产生InputSplit文件过程

        用户提交 MapReduce 作业后,JobClient 会调用 InputFormat 的 getSplit方法 生成 InputSplit 的信息.     一个 MapReduce 任务 ...

  6. HADOOP源码分析之RPC(1)

    源码位于Hadoop-common ipc包下 abstract class Server 构造Server protected Server(String bindAddress, int port ...

  7. Hadoop 源码分析(二四)FSNamesystem

    以下轮到FSNamesystem 出场了. FSNamesystem.java 一共同拥有4573 行.而整个namenode 文件夹下全部的Java 程序总共也仅仅有16876 行,把FSNames ...

  8. Hadoop源码分析(mapreduce.lib.partition/reduce/output)

    Map的结果,会通过partition分发到Reducer上.Reducer做完Reduce操作后,通过OutputFormat,进行输出.以下我们就来分析參与这个过程的类.   Mapper的结果, ...

  9. Hadoop源码分析之读文件时NameNode和DataNode的处理过程

    转自: http://blog.csdn.net/workformywork/article/details/21783861 从NameNode节点获取数据块所在节点等信息 客户端在和数据节点建立流 ...

随机推荐

  1. Educational Codeforces Round 11 B. Seating On Bus 水题

    B. Seating On Bus 题目连接: http://www.codeforces.com/contest/660/problem/B Description Consider 2n rows ...

  2. Hive集合数据类型

    Hive的列除了支持基本的数据类型外,还支持使用Struct.Map和Array三种集合数据类型. 假设某表有如下一行,我们用JSON格式来表示其数据结构.在Hive下访问的格式为 { "n ...

  3. 使用 dsc_extractor 导出 dyld_shared_cache_arm64

    iOS系统的全部Framework二进制被打包成一个cache文件,位于 /System/Library/Caches/com.apple.dyld 目录下,我们要想查看某个系统库的二进制需要将 dy ...

  4. 国内OCR供应商及其演示链接

    最近因为需要收集了一些OCR的供应商,可以做身份证识别,银行卡识别,名片识别等特定场景下的文字识别.在通用场景下的文字识别效果还不是很理想.现在OCR在特定的场景下做得已经很不错了.下面列出下这些厂商 ...

  5. Apache commons——Apache旗下的通用工具包项目

    Apache Commons是Apache旗下的一个开源项目,包含了很多开源的工具,用于解决平时编程经常会遇到的问题,减少重复劳动 这里是Apache commons的官方网站 下面是工具的简单介绍: ...

  6. 畅通工程_hdu_1232(并查集)

    畅通工程 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submi ...

  7. 富文本编辑器、日期选择器、软件天堂、防止XSS攻击、字体icon、转pdf

    [超好用的日期选择器] Layui:http://www.layui.com/laydate/ 备注:日期选择器,用过很多很多,自己也写过一些:相信这个简单而又不简单的选择器,能够给你多些美好的时光 ...

  8. 能使用html/css解决的问题就不要使用JS

    为什么说能使用html/css解决的问题就不要使用JS呢?两个字,因为简单.简单就意味着更快的开发速度,更小的维护成本,同时往往具有更好的体验,下面介绍几个实例. 1. 导航高亮 导航高亮是一种很常见 ...

  9. linux下svn的用法

    转载:http://blog.chinaunix.net/uid-22150747-id-189264.html 1.将文件checkout到本地目录 svn checkout path(path是服 ...

  10. XDroidRequest网络请求框架,新开源

    XDroidRequest 是一款网络请求框架,它的功能也许会适合你.这是本项目的第三版了,前两版由于扩展性问题一直不满意,思考来 思考去还是觉得Google的Volley的扩展性最强,于是借鉴了Vo ...