我对Map端spill的理解
一、先看简单理解
对于hadoop的map端配置项"mapreduce.task.io.sort.mb"和"mapreduce.map.sort.spill.percent"应该都比较熟悉了,如图解释(http://hadoop.apache.org/docs/current/hadoop-mapreduce-client/hadoop-mapreduce-client-core/MapReduceTutorial.html):

翻译成汉语的解释也有不少,随便粘一个"mapreduce.task.io.sort.mb 任务内部排序缓冲区大小,默认100","mapreduce.map.sort.spill.percent Map阶段溢写文件的阈值(排序缓冲区大小的百分比),默认0.8,也就是80%"。这些内容一点都不难理解,就是map的结果先放入缓冲区(其实先序列化),当缓冲区的数据量达到阈值时(默认100M * 0.8 = 80M),溢出行为会在一个后台线程执行开始spill操作。
二、发现问题
问题的核心在于mapreduce.map.sort.spill.percent这个配置。
前两天浏览官网(http://hadoop.apache.org/docs/current/hadoop-mapreduce-client/hadoop-mapreduce-client-core/MapReduceTutorial.html)时在上述两条配置的说明下面还有两条注意事项,其中主要疑问在第一条,如图:

只看第一条就行,我开始对这条英文的理解比较模糊,于是上网找了一些官网的翻译(http://blog.csdn.net/u011812294/article/details/53379338?locationNum=8&fps=1),如图:

虽然我对这段英文理解的比较模糊,但是也能看出这个翻译是明显错误的(只是就事论事,没有批评作者的意思,毕竟官网那么多英文都大体翻译了过来已经很了不起了,谁都有没有理解不是很透彻的地方,而且好多内容我都是看这篇翻译弄懂的),那到底会不会起额外的线程呢,spill到磁盘的数据是只有percent * buffer的数据量呢还是另有门道呢?这算是"疑问一"。于是我就又看了官网的mapred-default.xml文件对这个配置的说明,如图:

这解释前半部分没什么说的,后半部分透露出一个信息,当percent小于0.5的时候spill到磁盘的数据量有可能会大于percent * buffer,这又是为什么呢?这算是"疑问二"。下面就是我通过大量的请教别人和上网查资料之后,对这两个问题的解释。
三、解释两个疑问
对我帮助最大的应该是这篇文章"http://www.tuicool.com/articles/7FNN32",对此作者表示由衷的感谢。
要解释这两个疑问需要用到再稍微深一层的知识,我再这里只对深一层的东西做一个简单的抽象,能解决问题就行,例如实际有3个环形缓冲区,我只抽象成一个。
简单来说,map的输出到一个缓存区(中间还有个序列化过程不讨论),这个环形缓冲区有三个索引(或者指针),分别叫kvStart、kvEnd、kvIndex。map结果每进来一个keValue对,kvIndex更新一次,也就是始终标识下一个可用的地址,此时还没达到阈值,没有开始spill,kvStart=kvEnd,指向标识当spill开始时的起始位置,然后,阈值到了,后台开启一个spill线程,此时,kvStart暂时不变,而对kvEnd进行重新赋值,kvEnd=kvIndex,然后kvIndex不受影响继续随着map结果的写入而不断更新直到缓冲区满了为止。此时,spill要处理的数据其实已经确定了,就是kvStart到(kvEnd-1)这区间的数据进行溢写,此过程kvEnd正常情况不变,而每溢写成功一条数据kvStart好像是更新一次,直到最后spill成功时kvStart=kvEnd,为下一次的spill做准备。
上一段描述的是一般情况下的spill过程抽象,但是还是不能解释我提的两个疑问,其实从英文解释可以看的出我的两个疑问是些另外的情况,而这另外的情况指的就是percent小于0.5的可能会发生的情况。下面举例子说明这种情况。
例如mapreduce.map.sort.spill.percent=0.33,当缓冲区第一次达到阈值时,启动一个后台spill线程开始正常的溢写操作,由于缓冲区没满,map结果继续写入缓冲区(这一过程称为Collect),当又一个0.33*buffer被写入之后,便再次触发溢写过程,但是此时不会另外启动一个spill线程,不过呢kvEnd会被重新赋值,kvEnd被重新赋值之后呢,kvStart要到达新的kvEnd时才能结束,这样两次触发一共要处理的数据总量就是2 * 0.33 * buffer=0.66 * buffer了(当然也有可能出现3次出发,结果0.99 * buffer的情况),但是多次触发很明显只能是percent<0.5的情况,因为当percent>0.5时剩余buffer即使满了也达不到0.5,不能触发。
这样就很好的解释了这段英文"Note that collection will not block if this threshold is exceeded while a spill is already in progress, so spills may be larger than this threshold when it is set to less than .5"
还有一句英文"and the remainder of the buffer is filled while the spill runs, the next spill will include all the collected records, or 0.66 of the buffer, and will not generate additional spills",我感觉这还真有点灵活翻译理解的味道,关键字在于对"or"的理解,我认为翻译成"或者"并不是很恰当,而应该翻译成"也就是",换句话说,"0.66"就是对前面"all the collected records"用一种说法做的说明,而不是指的两种情况,当然"0.66"更不是指的percent=0.66了。至此,两个疑问都解释清楚了,当然底层模型我抽象的比较简单,要了解真正的过程看对我帮助最大的那篇文章,解释的非常详细,不过内容也十分多,需要自己找。
四、对spill过程中的锁做一个简单的摘抄,也来自文章"http://www.tuicool.com/articles/7FNN32"
两种信号:spillDone和spillReady,它们的逻辑如下:
1)对于写线程来说,如果写满了,就调用spillDone.await等待spillDone信号;否则不断往缓冲区里面写,到了一定程度,就发送spillReady.signal这个信号给读线程,发完这个信号后如果缓冲区没满,就释放锁继续写(这段代码无需锁),如果满了,就等待spillDone信号;
2)对于读线程来说,在平时调用spillReady.await等待spillReady这个信号,当读取之后(此时写线程要么释放锁了,要么调用spillDone.await在等待了,读线程肯定可以获得锁),则把锁释放掉,开始Spill(这段代码无需锁),完了读线程再次获取锁,修改相应参数,发送信号spillDone给写线程,表明Spill完毕。
要看更详细信息还是看这篇文章"http://www.tuicool.com/articles/7FNN32"。
我对Map端spill的理解的更多相关文章
- Hadoop on Mac with IntelliJ IDEA - 10 陆喜恒. Hadoop实战(第2版)6.4.1(Shuffle和排序)Map端 内容整理
下午对着源码看陆喜恒. Hadoop实战(第2版)6.4.1 (Shuffle和排序)Map端,发现与Hadoop 1.2.1的源码有些出入.下面作个简单的记录,方便起见,引用自书本的语句都用斜体表 ...
- Hadoop2.4.1 MapReduce通过Map端shuffle(Combiner)完成数据去重
package com.bank.service; import java.io.IOException; import org.apache.hadoop.conf.Configuration;im ...
- 项目中Map端内存占用的分析
最近在项目中开展重构活动,对Map端内存尽量要省一些,当前的系统中Map端内存最高占用大概3G左右(设置成2G时会导致Java Heap OOM).虽然个人觉得占用不算多,但是显然这样的结果想要试 ...
- hadoop的压缩解压缩,reduce端join,map端join
hadoop的压缩解压缩 hadoop对于常见的几种压缩算法对于我们的mapreduce都是内置支持,不需要我们关心.经过map之后,数据会产生输出经过shuffle,这个时候的shuffle过程特别 ...
- MapReduce在Map端的Combiner和在Reduce端的Partitioner
1.Map端的Combiner. 通过单词计数WordCountApp.java的例子,如何在Map端设置Combiner... 只附录部分代码: /** * 以文本 * hello you * he ...
- Hive Map 端OOM 异常
怪异现象:数据量不大,且不是Reduce端OOM,是Map端OOM Map Task运行的时候数据流中包含了非法字符例如:EOF.NOP等东西,导致BufferedReader读取和StreamDec ...
- Hadoop基础-Map端链式编程之MapReduce统计TopN示例
Hadoop基础-Map端链式编程之MapReduce统计TopN示例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.项目需求 对“temp.txt”中的数据进行分析,统计出各 ...
- hadoop map端的超时参数
目前集群上某台机器卡住导致出现大量的Map端任务FAIL,当定位到具体的机器上时,无法ssh或进去后terminal中无响应,退出的相关信息如下: [hadoop@xxx ~]$ Received d ...
- 项目中Map端数据处理不均匀性分析
Map任务的不均匀性 最近发现Map端数据越来越不均匀,而处理输入的数据,写到本地磁盘的数据量都差不多,我们随便拿出来两个attempt任务(当前map数量为64个),33和45,33的counter ...
随机推荐
- django User model
django User model operation this tutorial will guide us to know how to manipulate django User model. ...
- Ecshop出现问题 includes\lib_main.php on line 1329 includes\lib_base.php on line
php 5.3版本兼容问题不少,以上函数参数传递问题可以将lib_main.php on line 1329这句 $ext = end(explode('.', $tmp)); 改为 : $extsu ...
- 《jQuery权威指南》学习笔记之第2章 jQuery选择器
2.1 jQuery选择器概述 2.1.1 什么使选择器 2.1.2 选择器的优势: 代码更简单,完善的检测机制 1.代码更简单 示例2-1 使用javascript实现隔行变色 < ...
- MarkDown/reST 文档发布流水线
相信很多朋友都在使用Markdown或者restructuredText格式来编写一些技术文档,也会把这些文档放在github上分享给社区.GitHub提供了很好的Markdown格式解析支持,但是这 ...
- Oracle多关键字查询
因项目需要,在某查询页面的查询字段支持多关键字查询,支持空格隔开查询条件,故实现如下: 使用的原理是:ORACLE中的支持正则表达式的函数REGEXP_LIKE, '|' 指明两项之间的一个选择.例子 ...
- Golang爬虫示例包系列教程(一):pedaily.com投资界爬虫
Golang爬虫示例包 文件结构 自己用Golang原生包封装了一个爬虫库,源码见go get -u -v github.com/hunterhug/go_tool/spider ---- data ...
- ASP.NET Zero--8.一个例子(1)菜单添加
以一个商品分类管理功能来编写,代码尽量简单易懂.从一个实体开始,一直到权限控制,由浅到深一步步对功能进行完善. 1.打开语言文件 [..\MyCompanyName.AbpZeroTemplate.C ...
- Oracle DML容错处理(1)
Oracle dml操作过程中可能出现键重复或者数据类型不一致等问题,一般进行数据处理时候需要对这些可能出现的错误提前考虑,避免更新失败.Oralce给出了一些其他解决方案,以在不同场景下使用. 1. ...
- Extjs的GridPanel分页前后台完整代码实例
第一次写文章啊,有些冲动.最近在公司学习Extjs,做了一个分页的小实例和大家分享. 1.首先编写paging-grid.js文件,这是我在网上参考的例子改写的,大同小异. Ext.onReady(f ...
- c#dalegate invoke及AsyncCallback使用
public delegate void AsyncDelegate(); private AsyncDelegate asyncDl; asyncDl = new AsyncDeleg ...