MR运行慢的原因

  • 计算机性能
    • CPU、内存、磁盘健康、网络
  • IO操作
    • 数据倾斜
    • Map和Reduce数量设置不合理
    • Map运行时间过长,导致Reduce等待过久
    • 小文件过多
    • 大量不可分块的大文件
    • Spill溢写次数过多
    • Merge次数过多

优化方法

数据输入

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

    Map阶段

  3. 减少Spill溢写次数:通过调整_io.sort.mb_以及_sort.spill.percent_参数值,提高触发spill的内存上限,减少spill次数,从而减少io;

  4. 减少merge合并次数,通过调整_io.sort.factor_参数,增大merge文件数目,减少merge的次数,从而缩短MR处理时间;(此处的merge是合并溢写的文件)
  5. Map之后,不影响业务逻辑前提下,先进行Combine处理,减少IO;

    _io.sort.mb:环形缓冲区大小_ _sort.spill.percent:溢写的阈值_ _io.sort.factor:控制一次最多合并多少个文件_

Reduce阶段

  1. 合理设置Map和Reuce数:两个都不能设置太多或者太少。太少会导致task等待,延长处理时间;太多会导致Map、Reduce任务间资源竞争,造成处理超时等待等错误;
  2. 设置Map、Reduce共存:调整slowstart.completedmaps参数,使map运行到一定程度后,Reduce也开始运行,减少Reduce等待时间;
  3. 规避使用Reduce。因为Reudce在用于连接数据集的时候会产生大量的网络消耗(shuffle)
  4. 合理设置Reuce端的Buffer:默认情况下,数据达到一个阈值的时候,buffer中的数据会写入到磁盘,然后reduce从磁盘中获取所有的数据。也就是说Buffer和Reuce没有直接关联,中间存在多次写磁盘、读磁盘过程,既然有这么一个弊端,那么久可以通过参数配置,Buffer中的一部分数据直接传输给Reduce,从而减少IO开销;mapred.reduce.input.buffer.percent,默认为0.0,当值大于0的时候,会保留一定比例的内存读Buffer的数据直接拿给Reduce使用。这样一来设置buffer需要内存,Reduce计算也需要内存,所以需要根据作业需求进行调整;

    IO传输

  5. 采用数据压缩的方式,减少网路io的时间,例如安装snappy和lzo压缩编码器

  6. 使用SequenceFile二进制文件

    数据倾斜

  7. 抽样和范围分区:通过对原始数据进行抽样得到的结果集来预设分区边界值

  8. 自定义分区
  9. Combine,使用Combine可以大大减小数据倾斜。Combine的目的就是聚合并精简数据
  10. 采用Map join,尽量避免Reduce join

    常用调优参数

    参数参考 hadoop官网配置