文章目录
(164)MR跑得慢的原因
MR程序执行效率的瓶颈,或者说当你觉得你的MR程序跑的比较慢的时候,可以从以下两点来分析:
- 计算机性能
节点的CPU、内存、磁盘、网络等,这种属于硬件上的检查;
- IO操作上的检查
- 是否发生了数据倾斜?即单一reduce处理了绝大部分数据
- Map运行时间过长,导致Reduce一直在等待;
- 小文件过多。
(165)MR常用调优参数
Map阶段
Map阶段:
1)自定义分区,减少数据倾斜。即自定义分区类,继承Partitioner接口,重写getPartition();
2)减少环形缓冲区溢写的次数:
mapreduce.task.io.sort.mb
:shuffle的环形缓冲区大小,默认是100M,可以提高至200M;mapreduce.map.sort.spill.percent
:环形缓冲区的溢出阈值,默认是80%,可以提高至90%。即写到90%的时候才溢出。
这样做的目的是,减少环形缓冲区溢写后形成的文件的个数,减少后面步骤里分区合并的压力。
3)增加每次Merge合并次数:
mapreduce.task.io.sort.factor
:分区归并时,每次归并的文件数量。默认是10,可以提高到20(如果你的内存足够支撑的话,否则只能调小了)
4)在不影响业务结果的前提下,可以开启Combiner:
job.setCombinerClass(xxxReducer.class);
5)为了减少磁盘IO,对于Map的输出文件,可以采用snappy或者LZO压缩。
6)提高MapTask的内存上限:
mapreduce.map.memory.mb
:默认内存上限是1024MB。通常来讲,1G内存用来处理128M数据是绰绰有余的,可以根据128M数据对应1G内存的原则,对应提高内存。
7)调整MapTask的堆内存大小:
mapreduce.map.java.opts
:跟上面的内存参数保持一致就可以。控制java用的内存
8)增加MapTask的CPU核数。
mapreduce.map.cpu.vcores
:默认核数是1,对于计算密集型任务,可以增加CPU核数;
9)异常重试次数
mapreduce.map.maxattempts
:每个MapTask的最大重试次数,一旦重试次数超过该值,则认为MapTask运行失败,默认值是4。可以根据实际情况做加减。
Reduce阶段
Reduce阶段:
1)调整每个Reduce一次性从多少个MapTask拉取数据。
mapreduce.reduce.shuffle.parallelecopies
:默认是5,即每个Reduce一次最多拉5个MapTask里的数据,如果内存足够支撑,完全可以调成10;
2)调整所拉取数据,在内存缓冲的占比。
mapreduce.reduce.shuffle.input.buffer.percent
:控制内存buffer大小占ReduceTask可用内存的比例。默认是0.7,可以提高到0.8。毕竟在内存中缓存的数据越多,整体计算速度就越快。
3)控制归并排序时,可以使用的内存比例:
mapreduce.reduce.shuffle.merge.percent
:简单的说,就是归并排序时,可以使用的内存占Reduce总可用内存的比例,超过这个比例,就只能溢出到磁盘了。这个比例默认是0.66,最高可以提高到0.75。
4)调整ReduceTask的可用内存上限:
mapreduce.reduce.memory.mb
:默认可用内存上限为1024MB。同样的,128M数据对应1G内存原则。适当提升内存到4-6G。
5)调整ReduceTask的堆内存:
mapreduce.reduce.java.opts
6)调整ReduceTask的CPU核数:
mapreduce.reduce.cpu.vcores
:默认核数是1,可以提高到2-4个
7)最大重试次数:
mapreduce.reduce.maxattempts
:ReduceTask的最大重试次数,一旦重试次数超过该值,则认为运行失败。默认是4。
8)当MapTask的完成比例达到多少时,才会为ReduceTask申请资源:
mapreduce.job.reduce.slowstart.completedmaps
:默认是0.05,即有5%的MapTask完成任务后就可以为ReduceTask申请资源。
9)Task的超时时间:
mapreduce.task.timeout
:控制task的超时时间,默认是600000毫秒,即10min。如果一个Task,在10min内,没有数据进入,也没有数据输出,则直接退出该任务。如果你的程序对每条输出数据的处理时间很长,可适当调大这个参数。
10)如果可以不用Reduce,那就尽量不用。
(166)MR数据倾斜问题
直观来看,就是在大部分任务都已经完成了的情况下,还有少数任务仍在运行,这时候大概率就是发生了数据倾斜,分给那少数任务的数据太多了,导致它们一直没有处理完。
当发生数据倾斜后,我们可以从哪些角度考虑优化呢?
- 首先是检查是否是由于空值过多(key)造成的数据倾斜;
生产环境下,可以选择过滤掉空值;如果一定要保留空值的话,可以自定义分区,将空值加随机数打散分布。
- 能在Map阶段提前处理的,就在Map阶段提前处理。比如说Map阶段的Combiner、MapJoin等;
- 设置多个reduce个数;