这里主要针对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的页面入口(http://namenode:50030/jobdetai.jps)查看map和reduce进度,如果你发现reduce在33%时,map正好提早一点点到100%,那么这将是最佳的配比,因为reduce是在33%的时候完成了copy阶段,也就是说,map需要再reduce到达33%之前完成所有的map任务,准备好数据。千万不能让reduce在等待,但是可以让map先完成。

          OK!这个重点的搞完之后我们在看看两个息息相关的参数,io.sort.mb和mapred.child.java.opts。因为每一个map或是reduce进程都是一个task,都会对应启动一个JVM,所以其实java.opts也与你启动的map和reduce数以及别的一些jvm敏感的参数有关。既然task运行在JVM里面,那么,我这里所要提到的sort.mb 也是分配在JVM中的,这个值是用来设置到底我一个map sort的可用buffer大小是多少,如果map在内存中sort的结果达到一个特定的值,就会被spill进入硬盘。具体这个值是等于mb*io.sort.spill.percent.。按照通常的设置方式,为了让jvm发挥最佳性能,一般设置JVM的最大可用内存量为mb设置的内存量的两倍。那么mb的内存量又根据什么设置呢?它主要是与你的一个map的结果数据量有关。如果一个map的结果数据量为600M,那么如果你设置的mb*io.sort.spill.percent.=200M,那么将进行3次spill进入硬盘,然后map完成后再将数据从硬盘上取出进行copy。所以,这个mb设置如果是600M的话,那么就不需要进行这次硬盘访问了,节省了很多时间。但是最大的问题是内存耗费很大。如果mb是600M,那么jvm.opts将需要设置为1G以上,那么,按照上例,你同时启动16个map和8个reduce 的话,那么你的内存至少应该有24G。所以,这里的设置也要慎重,因为毕竟你的服务器还要跑很多其他的服务。

         下面就讲一下别的一些有影响的参数,按照一般的设置方法就可以。首先是针对磁盘和磁盘IO的,mapred.local.dir,这个参数最好设置的跟你的磁盘数相同,你的磁盘应该每一个磁盘都单独设置为RAID0,然后将所有磁盘配置成多路径在这个配置项下,那么HDFS在决定数据存储时会顺序循环存储,保证所有磁盘数据量的一致性,也提升了整体磁盘的IO速度。那么针对于网络,主要是有reduce和map同时运行时需要慎重考虑。mapred.reduce.parallel.copies与mapreduce.reduce.shuffle.maxfetchfailures这些参数都是对网络有一些影响的。第一个是reduce可以进行的最大并行拷贝线程数,这些线程会同时从不同的datanode上取map结果,而第二个出错重试次数过多对于很多我们的应用都是降低性能的一个问题。因为一般一个job重试了1次没有成功那基本以后无论怎么重试都是不会成功的,重试了不成功不要紧,关键是这个重试还大量的消耗系统的资源,让其他的线程可能也因为starvation 而进入重试状态,恶性循环了。如果说你的网络确实很成瓶颈,千兆网都达不到,那么建议打开mapred.compress.map.output压缩选项,并配置 mapred.map.output.compression.codec压缩编码格式,一般都会使用snappy,因为这种格式对于压缩和解压缩都相对较快。还有就是如果你的集群是异构的,有些机器性能好,有些差,那么建议打开mapred.reduce.tasks.speculative.execution推测性执行,有利于优化进程分配,提升集群性能。

  


yarn下的hdfs和mr性能调优参数一览表

mr核心的几个参数:
conf/mapred-site.xml:
mapreduce.task.io.sort.mb
任务内部排序缓冲区大小默认100m
mapreduce.map.sort.spill.percent
Map阶段溢写文件的阈值(排序缓冲区大小的百分比)默认0.8
mapreduce.reduce.shuffle.parallelcopies
Reduce Task启动的并发拷贝数据的线程数目默认5
mapreduce.map.memory.mb
每个Map Task需要的内存量默认1024m
mapreduce.map.java.opts
map的最大累计内存如:-Xmx1024M
mapreduce.reduce.memory.mb
每个Reduce Task需要的内存量默认1024m
mapreduce.reduce.java.opts
所有reduce加起来的总和内存大小如:-Xmx1024M 
mapreduce.job.jvm.num.tasks 
默认为1,设置为 -1,重用jvm
 
dfs io:
io.file.buffer.size
默认4k,根据需要适当调高
 
namenode性能调优参数:
dfs.namenode.handler.count
主要是namenode处理datanode的rpc进程数默认是100
 
其他参数:
mapreduce.job.reduce.slowstart.completed.maps 
默认值是0.05,也就是map task完成数目达到5%时,开始启动reduce task
 
下述意义不大
conf/yarn-site.xml
yarn.nodemanager.resource.memory-mb
NodeManager总的可用物理内存,默认值是8192MB,一般情况下不要修改
yarn.nodemanager.vmem-pmem-ratio
每使用1MB物理内存,最多可用的虚拟内存数默认2.1
yarn.nodemanager.resource.cpu-vcores
参数解释:NodeManager总的可用虚拟CPU个数。默认值:8