设为首页 加入收藏

TOP

hadoop学习(七)WordCount+Block+Split+Shuffle+Map+Reduce技术详解(二)
2014-11-24 03:16:26 来源: 作者: 【 】 浏览:10
Tags:hadoop 学习 WordCount Block Split Shuffle Map Reduce 技术 详解
问题不在这里,网上又有新的解释如:MapReduce中如何处理跨行Block和UnputSplit的问题。其实大致就是想说命Block与Split之间的区别,这里不再说明。

回到今天的重点:Shuffle

3、Shuffle过程:

Shuffle,也称Copy阶段。Reduce Task从各个Map Task上远程拷贝一片数据,并针对某一片数据,如果其大小超过一定阀值,则写到磁盘上,否则直接放到内存中。其实就是打乱,如在java API Collections.shuffle(List);方法里的随机的打乱参数list里的元素顺序。

在官方给的关于Shuffle过程的描述,很模糊,建议大家不要看了。还是看看大牛们是怎么总结Shuffle过程的吧。关于Shuffle,我们需要清楚Shuffle是怎样把map task的输出结果有效地传送到reduce端的。其实Shuffle描述的就是数据从map task 的输出到reduce task输入的这段过程。

在Hadoop这样的集群环境中,大部分map task与reduce task的执行是在不同的节点上。当然很多情况下Reduce执行时需要跨节点去拉取其它节点上的map task结果。如果集群正在运行的job有很多,那么task的正常执行对集群内部的网络资源消耗会很严重。这种网络消耗是正常的,我们不能限制,能做的 是最大化地减少不必要的消耗。还有在节点内,相比于内存,磁盘IO对job完成时间的影响也是可观的。从最基本的要求来说,我们对Shuffle过程的 期望可以有:

1)完整地从map task端拉取数据到Reduce端。

2)在跨节点拉取数据时,尽可能地减少对带宽的不必要消耗。

3)减少磁盘IO对task执行的影响。

到这里时,大家可以去想想,如果是自己来设计这段Shuffle过程,那么你的设计目标是什么能优化的地方主要在于减少拉取数据的量及尽量使用内存而不是磁盘。
这里根据博主指定的在Hadoop0.21.0的源码中的Shuffle过程。以WordCount为例,并假设它有8个map task和3个reduce task。而Shuffle过程横跨map与reduce两端。

3.1、Map阶段:

\

上图是某个map task的运行情况。图中清楚的指出partition、sort与combiner到底作用在哪个阶段。从这个图,可以清晰的了解map数据输出到map端所有数据准被好的全过程。

整个流程分为四步。简单可这样说,每个map task都有一个内存缓冲区,存储着map的输出结果,当缓冲区快满的时候需要将缓冲区的数据以一个临时文件的方式存放到磁盘,当整个map task 结束后在对磁盘中这个map task 产生的所有临时文件合并,生成最终的正式输出文件,然后等待reduce task来拉数据。

其实每一步都包含着多个步骤与细节:

1、在map task执行时,它的输入数据来源于HDFS的block,当然在MapReduce概念中,map task只读取split。Split与block的对应关系在上面我们已经说的很明白了。在WordCount例子里,假设map的输入数据都是像 “aaa”这样的字符串。
2、在经过mapper的运行后,我们得知mapper的输出是这样一个key/value对: key是“aaa”, value是数值1。因为当前map端只做加1的操作,在reduce task里才去合并结果集。前面我们知道这个job有3个reduce task,到底当前的“aaa”应该交由哪个reduce去做呢,是需要现在决定的。
MapReduce提供Partitioner接口,它的作用就是根据key或value及reduce的数量来决定当前的这对输出数据最终应该交由哪个 reduce task处理。默认对key hash后再以reduce task数量取模。默认的取模方式只是为了平均reduce的处理能力,如果用户自己对Partitioner有需求,可以订制并设置到job上。
在上面的例子中,“aaa”经过Partitioner后返回0,也就是这对值应当交由第一个reducer来处理。接下来,需要将数据写入内存缓冲区中,缓冲区的作用是批量收集map结果,减少磁盘IO的影响。我们的key/value对以及Partition的结果都会被写入缓冲区。当然写入之 前,key与value值都会被序列化成字节数组。 而整个内存缓冲区就是一个字节数组。
3、这个内存缓冲区是有大小限制的,默认是100MB。当map task的输出结果很多时,就可能会撑爆内存,所以需要在一定条件下将缓冲区中的数据临时写入磁盘,然后重新利用这块缓冲区。这个从内存往磁盘写数据的过程被称为Spill,中文可译为溢写这个溢写是由单独线程来完成,不影响往缓冲区写map结果的线程。溢写线程启动时不应该阻止map 的结果输出,所以整个缓冲区有个溢写的比例spill.percent。这个比例默认是0.8,也就是当缓冲区的数据已经达到阈值(buffer size * spill percent = 100MB * 0.8 = 80MB),溢写线程启动,锁定这80MB的内存,执行溢写过程。Map task的输出结果还可以往剩下的20MB内存中写,互不影响。
当溢写线程启动后,需要对这80MB空间内的key做排序(Sort)。排序是MapReduce模型默认的行为,这里的排序也是对序列化的字节做的排序。
在这里我们可以想想,因为map task的输出是需要发送到不同的reduce端去,而内存缓冲区没有对将发送到相同reduce端的数据做合并,那么这种合并应该是体现是磁盘文件中的。从官方图上也可以看到写到磁盘中的溢写文件是对不同的reduce端的数值做过合并。所以溢写过程一个很重要的细节在于,如果有很多个 key/value对需要发送到某个reduce端去,那么需要将这些key/value值拼接到一块,减少与partition相关的索引记录
在针对每个reduce端而合并数据时,有些数据可能像这样:“aaa”/1, “aaa”/1。对于Wordcount例子,就是简单地统计单词出现的次数,如果在同一个map task的结果中有很多个像“aaa”一样出现多次的key,我们就应该把它们的值合并到一块,这个过程叫reduce也叫combine。但 MapReduce的术语中,reduce只指reduce端执行从多个map task取数据做计算的过程。除reduce外,非正式地合并数据只能算做combine了。其实大家知道的,MapReduce中将Combiner等 同于Reducer。
如果client设置过Combiner,那么现在就是使用Combiner的时候了。将有相同key的key/value对的value加起来,减少溢写到磁盘的数据量。Combiner会优化MapReduce的中间结果,所以它在整个模型中会多次使用。那哪些场景才能使用Combiner呢?从这里分析,Combiner的输出是Reducer的输入,Combiner绝不能改变最终的计算结果。所以从我的想法来看,Combiner只应该用于那种 Reduce的输入key/value与输出key/value类型完全一致,且不影响最终结果的场景。比如累加,最

首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇saiku中文维度,补充说明 下一篇物流配送中商品订货数量的控制技术

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

·新书介绍《Python数 (2025-12-25 04:49:47)
·怎么利用 Python 进 (2025-12-25 04:49:45)
·金融界大佬力荐,Pyt (2025-12-25 04:49:42)
·你必须要弄懂的多线 (2025-12-25 04:22:35)
·如何在 Java 中实现 (2025-12-25 04:22:32)