Mapreduce 程序效率的瓶颈在于两点:

1. 计算机性能

CPU、内存、磁盘健康、网络
(所以万一MR跑得慢了,最简单的方式是提高计算及性能,加内存等等!)

2. I/O 操作优化

(1)数据倾斜
(2)map和reduce数设置不合理(切片问题)
(3)reduce等待过久
(4)小文件过多
(5)大量的不可分块的超大文件
(6)spill次数过多(磁盘溢写次数过多)
(7)merge次数过多等(因为要对数据进行归并排序)

mapreduce 优化方法

1. 数据输入:

(1)合并小文件:在执行mr任务前将小文件进行合并,大量的小文件会产生大量的map任务,增大map任务装载次数,而任务的装载比较耗时,从而导致 mr 运行较慢。
(2)采用ConbinFileInputFormat来作为输入,解决输入端大量小文件场景。

2. map阶段

(1)减少spill次数:通过调整io.sort.mb及sort.spill.percent参数值,增大触发spill的内存上限,减少spill次数,从而减少磁盘 IO。

注释:因为溢写的次数越多越耗时
     io.sort.mb是环形缓冲区的大小
     sort.spill.percent是默认百分之多少的时候进行溢写到磁盘

(2)减少merge次数:通过调整io.sort.factor参数,增大merge的文件数目,减少merge的次数,从而缩短mr处理时间。
(3)在 map 之后先进行combine处理,减少 I/O。

3. reduce阶段

(1)合理设置map和reduce数:两个都不能设置太少,也不能设置太多。太少,会导致task等待,延长处理时间;太多,会导致 map、reduce任务间竞争资源,造成处理超时等错误。
(2)设置map、reduce共存:调整slowstart.completedmaps参数,使map运行到一定程度后,reduce也开始运行,减少reduce的等待时间。
(3)规避使用reduce,因为Reduce在用于连接数据集的时候将会产生大量的网络消耗(减少shuffle的过程,因为shuffle过程很耗时,消耗的资源很多)

(4)合理设置reduc端的buffer,默认情况下,数据达到一个阈值的时候,buffer中的数据就会写入磁盘,然后reduce会从磁盘中获得所有的数据。也就是说,buffer和reduce是没有直接关联的,中间多个一个写磁盘->读磁盘的过程,既然有这个弊端,那么就可以通过参数来配置,使得buffer中的一部分数据可以直接输送到reduce,从而减少IO开销:mapred.job.reduce.input.buffer.percent,默认为0.0。当值大于0的时候,会保留指定比例的内存读buffer中的数据直接拿给reduce使用。这样一来,设置buffer需要内存,读取数据需要内存,reduce计算也要内存,所以要根据作业的运行情况进行调整。

4. IO传输

(1)采用数据压缩的方式,减少网络IO的的时间。安装Snappy和LZOP压缩编码器。
(2)使用SequenceFile二进制文件(SequenceFile这个格式比较紧凑,可以把小文件封装起来)

5. 数据倾斜问题

(1)数据倾斜现象

数据频率倾斜——某一个区域的数据量要远远大于其他区域。

数据大小倾斜——部分记录的大小远远大于平均值。

(2)如何收集倾斜数据

在reduce方法中加入记录map输出键的详细情况的功能。