shuffle和排序

shuffle属于不断被优化和改进的代码库,是MapReduce的“心脏”。

shuffle可以将其定义为:map的输出到reduce的输入(在一些语境中,代表reduce接受map输出的这部分)

map端


我们知道map产生的输出是临时写到本地磁盘的,但是他并不是简单的写到本地磁盘中,这个过程更为复杂,如图:

他会首先使用缓冲的方式写入到内存中,并且处于效率的考虑进行预排序。每个map都有一个缓冲区用于存储任务输出,这个缓冲区的大小默认为100MB,可以通过io.sort.mb属性调整。一旦缓冲的内容达到预设的阀值(通过io.sort.spill.percent,默认是0.8或80%),一个后台进程便把内容溢出(spill)到磁盘。在溢出过程map输出会继续写到缓冲区,如果在此期间被填满,则发生堵塞,直到写磁盘过程完成。这个溢出写的过程会将数据写到mapreduce.cluster.local.dir指定的目录内。在写硬盘之前会根据输出的reduce进行分区(partition),然后对每个分区内容进行排序,如果有combiner函数,则在排序之后执行combiner。每次内存缓冲区达到溢出的阀值,就会新建一个溢出文件(spill file)。最终会有几个溢出文件,这些溢出文件会被合并成一个已分区且已排序的输出文件,io.sort.factor控制一次最多能够合并多少流,默认是10。如果至少有3个溢出文件(这个值由min.num.spills.for.combine属性设置)则就会在输出文件写到磁盘之前在此运行以此combiner。将输出进行压缩可以减少输出及传递到reduce的网络开销,可以设置mapreduce.compress.map.output设置为true,使用mapreduce.map.output.compression.codec指定压缩方法。

reduce端

reduce任务需要集群中若干个map的输出作为其输入,但是每个map的完成时间并不一样,所以只要有一个map输出,reduce就开始复制其输出,这就是reduce端的复制阶段。reduce有少量的复制线程,默认是5个,这个值由mapreduce.reduce.parallel.copies属性改变。

那么reduce如何知道从哪台机器获取map输出呢?

map任务完成后,会通知其父tasktracker,tasktracker会通知jobtracker(在MR2中是applicationMaster),从而jobtracker(applicationMaster)知道了tasktracker与map的映射关系,reduce中的一个线程会定期向applicationMaster(或者jobtracker)进行询问,以便获取map输出的位置。

复制完成后,reduce开始进入排序阶段(其实是合并节阶段,因为排序是在map端进行的),这个阶段合并map输出,保持其排好的顺序。这个合并是循环进行的,可以设置合并因子io.sort.factor,默认是10,即每趟合并10个文件,假设总共50个map,总共进行5趟,最终有5个中文文件。之后是reduce阶段,直接把数据输入到reduce函数,而不用将这5个文件合并称一个大文件。reduce函数输出直接写到HDFS上。


配置调优

map端的调优属性:

属性名称类型默认值说明
io.sort.mbint 100map输出所使用的内存缓冲区大小,以MB为单位
io.sort.spill.percentfloat0.80缓冲区预设的阀值,超过这个百分比开始将内容溢到磁盘
io.sort.factoryint10排序文件时一次最多合并的流数,在reduce端也是用
min.num.spills.for.combineint3运行combiner所需要最少溢出文件数
mapreduce.compress.map.outputBooleanfalse压缩map输出
mapreduce.map.output.compression.codecClass Nameorg.apache.hadoop.
io.compress.DefaultCodec
用于map输出的压缩编码器
tasktracker.http.threadsint40每个tasktracker运行的线程数,用于将map输出到reduce,在YARN不适用

这个过程总的来说就是要为shuffle分配更多的内存,但是这时候可能还需要考虑到map函数和reduce函数能够得到足够运行的内。所以一般map函数和reduce函数在编写的时候尽量少占内存。map端可以通过避免多次溢出写磁盘来获得最佳性能,一次是最佳的情况。


reduce端的调优属性

属性名称类型默认值说明
mapreduce.reduce.parallel.copiesint5用于把map的输出复制到reduce的线程数
mapreduce.reduce.copy.backoffint300在声明失败之前,reducer获取一个map输出所花的最大时间,以秒
为单位,如果失败,reducer可以在此时间内尝试重传
io.sort.factorint10排序合并时的合并因子
mapreduce.job.shuffle.input.buffer.percentfloat0.70在shuffle阶段,分配给map输出的缓冲区占堆空间的百分比
mapreduce.iob.shuffle.merge.percentfloat0.66map输出缓冲区(上面定义的那个)的阀值使用比例,用于启动合并输出和磁盘溢出写的过程
mapreduce.inmem.merge.thresholdint1000启动合并输出和磁盘溢出写过程的map的输出的阀值数。0或更小,意味着没有阀值限制
mapreduce.iob.reduce.input.buffer.percentfloat0.0在reduce过程,在内存中保存map输出的空间占整个堆空间的比例。reduce阶段开始时
,内存中的map输出不能大于这个值


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值