MR运行慢的原因
- 计算机性能
- CPU、内存、磁盘健康、网络
- IO操作
- 数据倾斜
- Map和Reduce数量设置不合理
- Map运行时间过长,导致Reduce等待过久
- 小文件过多
- 大量不可分块的大文件
- Spill溢写次数过多
- Merge次数过多
优化方法
数据输入
- 合并小文件:在执行MR任务前将小文件进行合并。大量的小文件会产生大量的Map任务,增大Map任务的装载次数,而任务的装载比较耗时,从而导致MR运行慢
采用CombineTextInputFormat作为输入解决输入端大量小文件的场景;
Map阶段
减少Spill溢写次数:通过调整
_io.sort.mb_
以及_sort.spill.percent_
参数值,提高触发spill的内存上限,减少spill次数,从而减少io;- 减少merge合并次数,通过调整
_io.sort.factor_
参数,增大merge文件数目,减少merge的次数,从而缩短MR处理时间;(此处的merge是合并溢写的文件) - Map之后,不影响业务逻辑前提下,先进行Combine处理,减少IO;
_io.sort.mb:环形缓冲区大小_
_sort.spill.percent:溢写的阈值_
_io.sort.factor:控制一次最多合并多少个文件_
Reduce阶段
- 合理设置Map和Reuce数:两个都不能设置太多或者太少。太少会导致task等待,延长处理时间;太多会导致Map、Reduce任务间资源竞争,造成处理超时等待等错误;
- 设置Map、Reduce共存:调整slowstart.completedmaps参数,使map运行到一定程度后,Reduce也开始运行,减少Reduce等待时间;
- 规避使用Reduce。因为Reudce在用于连接数据集的时候会产生大量的网络消耗(shuffle)
合理设置Reuce端的Buffer:默认情况下,数据达到一个阈值的时候,buffer中的数据会写入到磁盘,然后reduce从磁盘中获取所有的数据。也就是说Buffer和Reuce没有直接关联,中间存在多次写磁盘、读磁盘过程,既然有这么一个弊端,那么久可以通过参数配置,Buffer中的一部分数据直接传输给Reduce,从而减少IO开销;mapred.reduce.input.buffer.percent,默认为0.0,当值大于0的时候,会保留一定比例的内存读Buffer的数据直接拿给Reduce使用。这样一来设置buffer需要内存,Reduce计算也需要内存,所以需要根据作业需求进行调整;
IO传输
采用数据压缩的方式,减少网路io的时间,例如安装snappy和lzo压缩编码器
-
数据倾斜
抽样和范围分区:通过对原始数据进行抽样得到的结果集来预设分区边界值
- 自定义分区
- Combine,使用Combine可以大大减小数据倾斜。Combine的目的就是聚合并精简数据
- 采用Map join,尽量避免Reduce join
常用调优参数
参数参考 hadoop官网配置