这里主要针对Mapreduce的性能调优。
这一两个月在做mapreduce的性能调优,有些心得,还是要记下来的,以郷后人~
这里主要涉及的参数包括:
HDFS:
dfs.block.size
Mapredure:
io.sort.mb
io.sort.spill.percent
mapred.local.dir
mapred.map.tasks & mapred.tasktracker.map.tasks.maximum
mapred.reduce.tasks & mapred.tasktracker.reduce.tasks.maximum
mapred.reduce.max.attempts
mapred.reduce.parallel.copies
mapreduce.reduce.shuffle.maxfetchfailures
mapred.child.java.opts
mapred.reduce.tasks.speculative.execution
mapred.compress.map.output & mapred.map.output.compression.codec
mapred.reduce.slowstart.completed.maps
这里一共列出了十六个参数,这十六个参数基本上能满足一般情况下,不针对特定场景应用的性能调优了,下面我将以Terasort为例,详述这些参数的作用已经如何配比调优。
Hadoop的HDFS作为mapreduce的基础分布式文件系统,对mapred的运行效果也有直接的影响。首先影响到我们的性能的参数就是block.size,在网络环境很好的集群中,建议将这个参数提升,大小可以到128或256或更大(默认64M)。
但是HDFS的影响也仅限于此,而且其配置项多数都是目录配置以及容错,还有备份数等等,这些对于我们性能调优意义不大。可以举一个例子,那就是备份数。这个参数主要是用于设置block在集群中的备份数,这些备份将按照某种规则分配在集群的各个机器上,默认是3备份。但是由于mapred的map需要输入数据,一般默认情况是一个map一个block,那么当你在集群起job,一个job拉起来N多的map在一个机器执行时,如果这个map的输入数据是本地的,那么显然map的执行将会更快,因为不需要等待网络传输。拿四个节点为例,如果你设置三备份,那么你不管存什么数据,任何一台机器上可以存数的你的数据的量都是3/4,。但是如果你设置为四备份,那么任意一个节点上都能完整的找到你的数据,那么不管你怎么起job,你的map都将是本地化的。但是带来的坏处就是磁盘开销过大,一般大型的集群也承受不了5备份以上的数据量,所以,基本无意义。
下面来谈谈重头戏,那就是mapred中的这些NB的参数。前置知识我相信大家都已经了解了(如果你还不了解mapred的运行机制,看这个也无意义...),首先数据要进行map,然后merge,然后reduce进程进行copy,最后进行reduce,其中的merge和copy总称可以为shuffle。在你起一个job前,hadoop需要知道你要启动多少个map,多少个renduce进程,如果你进行默认参数启动,那么默认只有一个map线程。(reduce也许也是一个..)这个速度是很慢的。设置map启动个数的参数是mapred.map.tasks,reduce则是mapred.reduce.tasks。这两个参数可以说是对整个集群的性能起主导型作用的参数,调试也基本上围绕这两个参数。那大家要问就两个参数有什么好来回修改的呢?其实,这两个参数的设置配比也直接影响到其他的参数的设置。首当其冲的就是mapred.tasktracker.map.tasks.maximum 以及 mapred.tasktracker.reduce.tasks.maximum。因为这两个参数设置了一台服务器上最多能同时运行的map和reduce数。现在我们来假设一个集群有一个namenode以及8个datanode,这是一个很客观的集群。我们假设上面的数据都是三备份,那么本地数据率为3/8。假设你设置的map.tasks=128,reuce.tasks=64,那么你的对应的两个maximum就应该分别为16以及8或是更高。因为这样才能保证你的所有map和reduce的任务都是分别同时启动的,如果你的设置reduce的maximum为7,那么你将得到非常糟糕的结果,因为这样8台机器同时可以运行的reduce数量为56了,比你设置的64差8个进程,这八个进程将会处于pending状态,直到某些正在运行的reduce完成它才能补上运行,势必大幅度的增加了运行时间。当然,这也不是越大越好,因为map有很长的一段时间是和reduce进程共存的,共存的时间取决于你设置的mapred.reduce.slowstart.completed.maps,如果你设置为0.6.那么reduce将在map完成60%后进入运行态。所以说,如果你设置的map和reduce参数都很大,势必造成map和reduce争抢资源,造成有些进程饥饿,超时出错,最大的可能就是socket.timeout的出错,网络过于繁忙。所以说,这些需要根据集群的性能,适当调试添加和减少,以达到最好的效果。那么,map和reduce之间是怎样的配比比较好呢?apache官网给了我们一些建议,比如设置reduce与map,他们之间有一个具体的公式。但是实际情况总是不能用公式来套用的(否则就不需要系统工程师了...)。一般情况下,当你设置好map和reduce进程数后,你可以通过hadoop的mapred的页面入口(:50030/jobdetai.jps)查看map和reduce进度,如果你发现reduce在33%时,map正好提早一点点到100%,那么这将是最佳的配比,因为reduce是在33%的时候完成了copy阶段,也就是说,map需要再reduce到达33%之前完成所有的map任务,准备好数据。千万不能让reduce在等待,但是可以让map先完成。