MapReduce数据倾斜与优化

举报
Smy1121 发表于 2019/06/20 15:09:53 2019/06/20
【摘要】 MapReduce 优化 Combiner和Partitioner是用来优化MapReduce的,可以提高MapReduce的运行效率。下面我们来具体学习这两个组件。Combiner 我们以WordCount为例,首先通过下面的示意图直观的了解一下Combiner的位置和作用。 从上图可以看出,Combiner介于 Mapper和Reducer...

MapReduce 优化

        Combiner和Partitioner是用来优化MapReduce的,可以提高MapReduce的运行效率。下面我们来具体学习这两个组件。


Combiner

        我们以WordCount为例,首先通过下面的示意图直观的了解一下Combiner的位置和作用。

image.png


           从上图可以看出,Combiner介于 Mapper和Reducer之间,combine作为 Map任务的一部分,执行完 map 函数后紧接着执行combine,而reduce 必须在所有的 Map 任务完成后才能进行。 而且还可以看出combine的过程与reduce的过程类似,都是对相同的单词key合并其词频,很多情况下可以直接使用reduce函数来完成Combiner过程。


        通过上面的分析,下面我们将深入理解 Combiner组件。


        1、Combiner可以看做局部的Reducer(local reducer)。

        1)Combiner作用是合并相同的key对应的value。

        2)在Mapper阶段,不管Combiner被调用多少次,都不应改变 Reduce的输出结果。

        3)Combiner通常与Reducer的逻辑是一样的,一般情况下不需要单独编写Combiner,直接使用Reducer的实现就可以了。

        4)Combiner在Job中是如下设置的。


        job.setCombinerClass(Reducer.class);//Combiner一般情况下,默认使用Reducer的实现


        2、Combiner的好处

        1)能够减少Map Task输出的数据量(即磁盘IO)。我们前面提到Map Task 将输出的数据写到本地磁盘,它输出的数据量越多,它写入磁盘的数据量就越大,那么开销就越大,速度就越慢。

        2)能够减少Reduce-Map网络传输的数据量(网络IO)。这个很好理解,Map Task 输出越少,Reduce从Map结果中拉取的数据量就越少,自然就减少了网络传输的数据量。


        3、Combiner 的使用场景

        1)并不是所有的场景都可以使用Combiner,必须满足结果可以累加。

        2)适合于Sum()求和,并不适合Average()求平均数。例如,求0、20、10、25和15的平均数,直接使用Reduce求平均数Average(0,20,10,25,15),得到的结果是14, 如果先使用Combiner分别对不同Mapper结果求平均数,Average(0,20,10)=10,Average(25,15)=20,再使用Reducer求平均数Average(10,20),得到的结果为15,很明显求平均数并不适合使用Combiner。


Partitioner

        我们通过如下示意图,很直观的看到 Partitioner 的位置和作用。

image.png


从上图我们可以看出,Partitioner 处于 Mapper阶段,当Mapper处理好数据后,这些数据需要经过Partitioner进行分区,来选择不同的Reducer处理,从而将Mapper的输出结果均匀的分布在Reducer上面执行。


        通过上面的分析,下面我们将深入理解 Partitioner组件。

        1、Partitioner决定了Map Task 输出的每条数据交给哪个Reduce Task 来处理。Partitioner 有两个功能:

        1)均衡负载。它尽量将工作均匀地分配给不同的 Reduce。

        2)效率。它的分配速度一定要非常快。


        2、Partitioner 的默认实现:hash(key) mod R,这里的R代表Reduce Task 的数目,意思就是对key进行hash处理然后取模。很多情况下,用户需要自定义 Partitioner,比如“hash(hostname(URL)) mod R”,它确保相同域名下的网页交给同一个 Reduce Task 来处理。 用户自定义Partitioner,需要继承Partitioner类,实现它提供的一个方法:


getPartition(Text key, Text value, int numPartitions);

前两个参数分别为Map的key和value。numPartitions 为 Reduce 的个数,用户可以自己设置。


Partitioner 和 Combiner 先后关系

image.png


MapReduce 数据倾斜

数据分布:

正常的数据分布理论上都是倾斜的,就是我们所说的20-80原理:80%的财富集中在20%的人手中, 80%的用户只使用20%的功能 , 20%的用户贡献了80%的访问量 。


产生原因:

Mapreduce程序在运行的时候,运行了大部分,但是还有部分reduce还在运行,甚至长时间运行,最终导致整个程序运行时间很长才结束。


造成这种现象的主要原因是:

reduce程序处理的key的条数比其他key的条数大很多,这也就造成了分配到数据巨大的key的节点长时间运行。本质讲数据倾斜就是数据分布不均。


出现场景:

不同的数据字段可能的数据倾斜一般有两种情况:


一种是唯一值非常少,极少数值有非常多的记录值(唯一值少于几千)

一种是唯一值比较多,这个字段的某些值有远远多于其他值的记录数,但是它的占比也小于百分之一或千分之一


解决方案:

方式1:增加reduce 的jvm内存

既然reduce 本身的计算需要以合适的内存作为支持,在硬件环境容许的情况下,增加reduce 的内存大小显然有改善数据倾斜的可能,这种方式尤其适合数据分布第一种情况,单个值有大量记录, 这种值的所有纪录已经超过了分配给reduce 的内存,无论你怎么样分区这种情况都不会改变。


方式2: 增加reduce 个数

这个对于数据分布第二种情况有效,唯一值较多,单个唯一值的记录数不会超过分配给reduce 的内存. 如果发生了偶尔的数据倾斜情况,增加reduce 个数可以缓解偶然情况下的某些reduce 不小心分配了多个较多记录数的情况. 但是对于第一种数据分布无效。


方式3: 自定义partition

如果map输出键的单词来源于一本书。其中大部分必然是省略词(stopword: a,the,or )。那么就可以将自定义分区将这部分省略词发送给固定的一部分reduce实例。而将其他的都发送给剩余的reduce实例。


方式4:设定combiner

减少流向reduce的文件数量,从而减轻reduce数据倾斜。


【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。