mapreduce性能调优
mapreduce程序常用调优方法。
1、mapreduce参数配置优化
map端:
map执行输出时首先是保存在缓存中,这个缓存的默认大小是100MB,由参数io.sort.mb来控制。当缓存达到一定比例时,缓存中数据将写入磁盘中,这个比例由io.sort.spill.percent来控制。在缓存写入磁盘之前,可以看到还有一个分割、排序和合并的过程。缓存中的数据在每次输出到磁盘时都会生成一个临时文件,多个临时文件合并后生成一个map输出文件,参数io.sort.factor指定了最多可以有多少个临时文件被合并到输出文件中。
combine:
mapreduce框架提供了combine机制提高数据传输效率,参数min.num.spills.for.combine指定了当产生多少个临时文件时会执行一次combine操作。
map端的数据可以通过多个http线程的方式传送给reducer节点,参数tracker.http.threads可以指定每个tasktracker上的http文件传送线程的数值(mapreduce2中已取消功能,有系统自动控制)。
reducer端:
reduce节点可以在map任务完成时通过多个线程读取多个map任务的输出,线程数由参数mapred.reduce.parallel.copies设定。在reduce任务的tasktracker节点上,可以设置mapred.job.shuffle.input.buffer.percent控制读取的map输出数据的缓冲占整个内存的百分比。当缓存中的数据达到mapred.job.shuffle.merge.percent设定的数值或超过map的输出阈值(mapred.inmem.merge.threshold)时,缓存中的数据会写入磁盘。
数据进入reduce之前会先进行合并,io.sort.factor参数指定了多少个map输出数据文件会合并为一个文件由reduce处理。
除map、reduce阶段的可控参数外,还有例如jvm内存大小、文件缓存单元大小等参数,影响着mapreduce作业的性能。
参数表:
参数 | 单位 | 默认值 | 说明 |
io.sort.mb | int | 100 | map输出的缓存大小,单位MB |
io.sort.spill.percent | float | 0.8 | map输出缓存占用超过此比例将开始写入磁盘。 |
io.sort.factor | int | 10 | 合并多个临时文件的数量 |
min.num.spills.for.combine | int | 3 | 输出临时文件达到次数时会执行一次combine操作。 |
tasktracker.http.threads | int | 40 | tasktracker可用于输出map文件的http线程数。 |
mapred.reduce.parallel.copies | int | 5 | 可读取多个map输出的线程数 |
mapred.reduce.copy.backoff | int | 300 | reduce读取map输出的失败超时时间,单位s |
io.sort.factor | int | 10 | 处理之前合并文件的最大数 |
mapred.job.shuffle.input.buffer.percent | float | 0.7 | 存储map输出数据的缓存占整个内存的比例 |
mapred.job.shuffle.merge.percent | float | 0.66 | 存储map输出数据的缓存占用比例阈值,超过则写入磁盘。 |
mapred.inmem.merge.threshold | int | 1000 | 当map输出文件超过此数值时,进行合并并存入磁盘。 |
mapred.iob.reduce.input.buffer.percent | float | 0.0 | 在reduce接到的内存中保持map输出数据的缓冲占整个内存的百分比,增大可减少磁盘读写。 |
mapred.child.java.ops | int | 200 | map或reduce任务可使用的内存大小,默认200mb,可适当增大。 |
io.file.buffer.size | int | 4096 | 进行磁盘I/o操作的缓存大小,默认是4KB,可提升到64kB或者128KB |
2、启用数据压缩
压缩功能设置参数 |
|
|
|
参数 | 类型 | 默认值 | 说明 |
mapred.compress.map.output | boolean | false | 是否启用map输出压缩 |
mapred.map.output.compression.codec | class name | org.apache.hadoop.io.compress.DefaultCodec | map输出压缩类 |
只需把mapred.compress.map.output参数设置为true即可启用压缩功能。
hadoop提供的内置压缩方式:
1)DefaultCodec:采用zlib压缩格式
2)GzipCodec:采用Gzip压缩格式
3)BZipCodec:采用bzip2压缩格式
示例代码:
Configurationconf = new Configuration();
conf.setBoolean("mapred.output.compress",true);
conf.setClass(“mapred.output.compression.codec",GzipCodec.class, CompressionCodec.class);
3、使用预测执行功能
hadoop集群在进行计算时,底层节点的故障是不可避免的。有些会减慢节点的处理速度而有些直接导致节点崩溃。例如:磁盘的数据隧道损坏导致寻址困难、网络丢包导致数据传输慢等。当故障发生时,节点上的任务将被拖慢,当被拖慢的任务是map时,由于reduce任务依赖于所有map任务,所以将会严重影响整个集群的执行效率。为了改善这样的情况,hadoop设计了预测执行机制。
在执行任务的过程中,hadoop会监测所有任务的进度和完成情况,当出现某个任务执行进度慢于整个系统中的平均进度时,hadoop预测这个任务将会拖慢整个作业的进展,此时,hadoop将在另外的节点上启动一个相同的任务,并于原始任务并行执行。当原始任务和备份任务中的一个完成时,另一个任务将被终止。这一过程被称为预测执行。
在默认情况下,预测执行机制是开启的,也可以单独配置map或reduce任务的默认执行机制的开启状态。
参数 | 类型 | 默认值 | 说明 |
mapred.map.tasks.speculative.execution | boolean | true | 是否启用map任务的预测执行机制 |
mapred.reduce.tasks.speculative.execution | boolean | true | 是否启用reduce任务的预测执行机制 |
4、重用JVM
在启动map或者reduce任务是,tasktracker是在单独的jvm中启动进行的。默认每个jvm只可以运行一个task,其主要目的是避免某个任务的崩溃影响其他任务或整个tasktracker的正常运行。mapreduce也可以允许一个jvm运行多个任务。控制jvm执行的任务的参数是mapred.job.reuser.jvm.num.tasks,或调用jobconf类的setNumTasksToExecute PerJvm接口。当这个参数设置为-1时,一个jvm可以运行的任务数量没有限制。
重用jvm可以减少启动jvm的额外开销。对于一些map函数初始化较为简单但执行次数频繁的作业,重用jvm可以减少额外开销,提高系统的整体效率。