`
zcwfeng
  • 浏览: 106518 次
  • 性别: Icon_minigender_1
  • 来自: 吉林
社区版块
存档分类
最新评论

MapReduce提高效率的几点建议

 
阅读更多
Cloudera提供给客户的服务内容之一就是调整和优化MapReduce job执行性能。MapReduce和HDFS组成一个复杂的分布式系统,并且它们运行着各式各样用户的代码,这样导致没有一个快速有效的规则来实现优化代码性能的目的。在我看来,调整cluster或job的运行更像一个医生对待病人一样,找出关键的“症状”,对于不同的症状有不同的诊断和处理方式。

在医学领域,没有什么可以代替一位经验丰富的医生;在复杂的分布式系统上,这个道理依然正确—有经验的用户和操作者在面对很多常见问题上都会有“第六感”。我曾经为Cloudera不同行业的客户解决过问题,他们面对的工作量、数据集和cluster硬件有很大区别,因此我在这方面积累了很多的经验,并且想把这些经验分享给诸位。

在这篇blog里,我会高亮那些提高MapReduce性能的建议。前面的一些建议是面向整个cluster的,这可能会对cluster 操作者和开发者有帮助。后面一部分建议是为那些用Java编写MapReduce job的开发者而提出。在每一个建议中,我列出一些“症状”或是“诊断测试”来说明一些针对这些问题的改进措施,可能会对你有所帮助。

请注意,这些建议中包含很多我以往从各种不同场景下总结出来的直观经验。它们可能不太适用于你所面对的特殊的工作量、数据集或cluster,如果你想使用它,就需要测试使用前和使用后它在你的cluster环境中的表现。对于这些建议,我会展示一些对比性的数据,数据产生的环境是一个4个节点的cluster来运行40GB的Wordcount job。应用了我以下所提到的这些建议后,这个job中的每个map task大概运行33秒,job总共执行了差不多8分30秒。

第一点 正确地配置你的Cluster
诊断结果/症状:
1. Linux top命令的结果显示slave节点在所有map和reduce slot都有task运行时依然很空闲。
2. top命令显示内核的进程,如RAID(mdX_raid*)或pdflush占去大量的CPU时间。
3. Linux的平均负载通常是系统CPU数量的2倍。
4. 即使系统正在运行job,Linux平均负载总是保持在系统CPU数量的一半的状态。
5. 一些节点上的swap利用率超过几MB

优化你的MapReduce性能的第一步是确保你整个cluster的配置文件被调整过。对于新手,请参考这里关于配置参数的一篇blog:配置参数。 除了这些配置参数 ,在你想修改job参数以期提高性能时,你应该参照下我这里的一些你应该注意的项:

1. 确保你正在DFS和MapReduce中使用的存储mount被设置了noatime选项。这项如果设置就不会启动对磁盘访问时间的记录,会显著提高IO的性能。

2. 避免在TaskTracker和DataNode的机器上执行RAID和LVM操作,这通常会降低性能

3. 在这两个参数mapred.local.dirdfs.data.dir 配置的值应当是分布在各个磁盘上目录,这样可以充分利用节点的IO读写能力。运行 Linux sysstat包下的iostat -dx 5命令可以让每个磁盘都显示它的利用率。

4. 你应该有一个聪明的监控系统来监控磁盘设备的健康状态。MapReduce job的设计是可容忍磁盘失败,但磁盘的异常会导致一些task重复执行而使性能下降。如果你发现在某个TaskTracker被很多job中列入黑名单,那么它就可能有问题。

5. 使用像Ganglia这样的工具监控并绘出swap和网络的利用率图。如果你从监控的图看出机器正在使用swap内存,那么减少mapred.child.java.opts属性所表示的内存分配。

基准测试:
很遗憾我不能为这个建议去生成一些测试数据,因为这需要构建整个cluster。如果你有相关的经验,请把你的建议及结果附到下面的留言区。

第二点 使用LZO压缩
诊断结果/症状:
1. 对 job的中间结果数据使用压缩是很好的想法。
2. MapReduce job的输出数据大小是不可忽略的。
3. 在job运行时,通过linux top 和 iostat命令可以看出slave节点的iowait利用率很高。

几乎每个Hadoop job都可以通过对map task输出的中间数据做LZO压缩获得较好的空间效益。尽管LZO压缩会增加一些CPU的负载,但在shuffle过程中会减少磁盘IO的数据量,总体上总是可以节省时间的。

当一个job需要输出大量数据时,应用LZO压缩可以提高输出端的输出性能。这是因为默认情况下每个文件的输出都会保存3个幅本,1GB的输出文件你将要保存3GB的磁盘数据,当采用压缩后当然更能节省空间并提高性能。

为了使LZO压缩有效,请设置参数mapred.compress.map.output值为true。

基准测试:
在我的cluster里,Wordcount例子中不使用LZO压缩的话,job的运行时间只是稍微增加。但FILE_BYTES_WRITTEN计数器却从3.5GB增长到9.2GB,这表示压缩会减少62%的磁盘IO。在我的cluster里,每个数据节点上磁盘数量对task数量的比例很高,但Wordcount job并没有在整个cluster中共享,所以cluster中IO不是瓶颈,磁盘IO增长不会有什么大的问题。但对于磁盘因很多并发活动而受限的环境来说,磁盘IO减少60%可以大幅提高job的执行速度。

第三点 调整map和reduce task的数量到合适的值
诊断结果/症状:
1. 每个map或reduce task的完成时间少于30到40秒。
2. 大型的job不能完全利用cluster中所有空闲的slot。
3. 大多数map或reduce task被调度执行了,但有一到两个task还在准备状态,在其它task完成之后才单独执行

调整job中map和reduce task的数量是一件很重要且常常被忽略的事情。下面是我在设置这些参数时的一些直观经验:

1. 如果每个task的执行时间少于30到40秒,就减少task的数量。Task的创建与调度一般耗费几秒的时间,如果task完成的很快,我们就是在浪费时间。同时,设置JVM重用也可以解决这个问题。

2. 如果一个job的输入数据大于1TB,我们就增加block size到256或者512,这样可以减少task的数量。你可以使用这个命令去修改已存在文件的block size: hadoop distcp -Ddfs.block.size=$[256*1024*1024] /path/to/inputdata /path/to/inputdata-with/largeblocks。在执行完这个命令后,你就可以删除原始的输入文件了(/path/to/inputdata)。

3. 只要每个task运行至少30到40秒,那么就增加map task的数量,增加到整个cluster上map slot总数的几倍。如果你的cluster中有100个map slot,那就避免运行一个有101个map task的job — 如果运行的话,前100个map同时执行,第101个task会在reduce执行之前单独运行。这个建议对于小型cluste和小型job是很重要的。

4. 不要调度太多的reduce task — 对于大多数job来说,我们推荐reduce task的数量应当等于或是略小于cluster中reduce slot的数量。

基准测试:
为了让Wordcount job有很多的task运行,我设置了如下的参数:Dmapred.max.split.size=$[16*1024*1024]。以前默认会产生360个map task,现在就会有2640个。当完成这个设置之后,每个task执行耗费9秒,并且在JobTracker的Cluster Summar视图中可以观看到,正在运行的map task数量在0到24之间浮动。job在17分52秒之后结束,比原来的执行要慢两倍多。

第四点 为job添加一个Combiner
诊断结果/症状:
1. job在执行分类的聚合时,REDUCE_INPUT_GROUPS计数器远小于REDUCE_INPUT_RECORDS计数器。
2. job执行一个大的shuffle任务(例如,map的输出数据每个节点就是好几个GB)。
3. 从job计数器中看出,SPILLED_RECORDS远大于MAP_OUTPUT_RECORDS。

如果你的算法涉及到一些分类的聚合,那么你就可以使用Combiner来完成数据到达reduce端之前的初始聚合工作。MapReduce框架很明智地运用Combiner来减少写入磁盘以及通过网络传输到reduce端的数据量。

基准测试:
我删去Wordcount例子中对setCombinerClass方法的调用。仅这个修改就让map task的平均运行时间由33秒增长到48秒,shuffle的数据量也从1GB提高到1.4GB。整个job的运行时间由原来的8分30秒变成15分42秒,差不多慢了两倍。这次测试过程中开启了map输出结果的压缩功能,如果没有开启这个压缩功能的话,那么Combiner的影响就会变得更加明显。

第五点 为你的数据使用最合适和简洁的Writable类型
诊断/症状:
1. Text 对象在非文本或混合数据中使用。
2. 大部分的输出值很小的时候使用IntWritable 或 LongWritable对象。

当一个开发者是初次编写MapReduce,或是从开发Hadoop Streaming转到Java MapReduce,他们会经常在不必要的时候使用Text 对象。尽管Text对象使用起来很方便,但它在由数值转换到文本或是由UTF8字符串转换到文本时都是低效的,且会消耗大量的CPU时间。当处理那些非文本的数据时,可以使用二进制的Writable类型,如IntWritable, FloatWritable等。

除了避免文件转换的消耗外,二进制Writable类型作为中间结果时会占用更少的空间。当磁盘IO和网络传输成为大型job所遇到的瓶颈时,减少些中间结果的大小可以获得更好的性能。在处理整形数值时,有时使用VIntWritable或VLongWritable类型可能会更快些—这些实现了变长整形编码的类型在序列化小数值时会更节省空间。例如,整数4会被序列化成单字节,而整数10000会被序列化成两个字节。这些变长类型用在统计等任务时更加有效,在这些任务中我们只要确保大部分的记录都是一个很小的值,这样值就可以匹配一或两个字节。

如果Hadoop自带的Writable类型不能满足你的需求,你可以开发自己的Writable类型。这应该是挺简单的,可能会在处理文本方面更快些。如果你编写了自己的Writable类型,请务必提供一个RawComparator类—你可以以内置的Writable类型做为例子。

基准测试:
对于Wordcount例子,我修改了它在map计数时的中间变量,由IntWritable改为Text。并且在reduce统计最终和时使用Integer.parseString(value.toString)来转换出真正的数值。这个版本比原始版本要慢近10%—整个job完成差不多超过9分钟,且每个map task要运行36秒,比之前的33秒要慢。尽量看起来整形转换还是挺快的,但这不说明什么情况。在正常情况下,我曾经看到过选用合适的Writable类型可以有2到3倍的性能提升的例子。

第六点 重用Writable类型
诊断/症状:
1. 在mapred.child.java.opts参数上增加-verbose:gc -XX:+PriintGCDetails,然后查看一些task的日志。如果垃圾回收频繁工作且消耗一些时间,你需要注意那些无用的对象。
2. 在你的代码中搜索"new Text" 或"new IntWritable"。如果它们出现在一个内部循环或是map/reduce方法的内部时,这条建议可能会很有用。
3. 这条建议在task内存受限的情况下特别有用。

很多MapReduce用户常犯的一个错误是,在一个map/reduce方法中为每个输出都创建Writable对象。例如,你的Wordcout mapper方法可能这样写:

Java代码 收藏代码
  1. publicvoidmap(...){
  2. for(Stringword:words){
  3. output.collect(newText(word),newIntWritable(1));
  4. }
  5. }


这样会导致程序分配出成千上万个短周期的对象。Java垃圾收集器就要为此做很多的工作。更有效的写法是:

Java代码 收藏代码
  1. classMyMapper…{
  2. TextwordText=newText();
  3. IntWritableone=newIntWritable(1);
  4. publicvoidmap(...){
  5. for(Stringword:words){
  6. wordText.set(word);
  7. output.collect(wordText,one);
  8. }
  9. }
  10. }

基准测试:
当我以上面的描述修改了Wordcount例子后,起初我发现job运行时与修改之前没有任何不同。这是因为在我的cluster中默认为每个task都分配一个1GB的堆大小 ,所以垃圾回收机制没有启动。当我重新设置参数,为每个task只分配200MB的堆时,没有重用Writable对象的这个版本执行出现了很严重的减缓 —job的执行时间由以前的大概8分30秒变成现在的超过17分钟。原始的那个重用Writable的版本,在设置更小的堆时还是保持相同的执行速度。因此重用Writable是一个很简单的问题修正,我推荐大家总是这样做。它可能不会在每个job的执行中获得很好的性能,但当你的task有内存限制时就会有相当大的区别。

第七点 使用简易的剖析方式查看task的运行
这是我在查看MapReduce job性能问题时常用的一个小技巧。那些不希望这些做的人就会反对说这样是行不通的,但是事实是摆在面前。

为了实现简易的剖析,可以当job中一些task运行很慢时,用ssh工具连接上task所在的那台task tracker机器。执行5到10次这个简单的命令 sudo killall -QUIT java(每次执行间隔几秒)。别担心,不要被命令的名字吓着,它不会导致任何东西退出。然后使用JobTracker的界面跳转到那台机器上某个task的stdout 文件上,或者查看正在运行的机器上/var/log/hadoop/userlogs/目录中那个task的stdout文件。你就可以看到当你执行那段命令时,命令发送到JVM的SIGQUIT信号而产生的栈追踪信息的dump文件。([]在JobTracker的界面上有Cluster Summary的表格,进入Nodes链接,选中你执行上面命令的server,在界面的最下方有Local Logs,点击LOG进入,然后选择userlogs目录,这里可以看到以server执行过的jobID命名的几个目录,不管进入哪个目录都可以看到很多task的列表,每个task的log中有个stdout文件,如果这个文件不为空,那么这个文件就是作者所说的栈信息文件)

解析处理这个输出文件需要一点点以经验,这里我介绍下平时是怎样处理的:
对于栈信息中的每个线程,很快地查找你的java包的名字(假如是com.mycompany.mrjobs)。如果你当前线程的栈信息中没有找到任何与你的代码有关的信息,那么跳到另外的线程再看。

如果你在某些栈信息中看到你查找的代码,很快地查阅并大概记下它在做什么事。假如你看到一些与NumberFormat相关的信息,那么此时你需要记下它,暂时不需要关注它是代码的哪些行。

转到日志中的下一个dump,然后也花一些时间做类似的事情然后记下些你关注的内容。

在查阅了4到5个栈信息后,你可能会意识到在每次查阅时都会有一些似曾相识的东西。如果这些你意识到的问题是阻碍你的程序变快的原因,那么你可能就找到了程序真正的问题。假如你取到10个线程的栈信息,然后从5个里面看到过NumberFormat类似的信息,那么可能意味着你将50%的CPU浪费在数据格式转换的事情上了。

当然,这没有你使用真正的分析程序那么科学。但我发现这是一种有效的方法,可以在不需要引入其它工具的时候发现那些明显的CPU瓶颈。更重要的是,这是一种让你会变的更强的技术,你会在实践中知道一个正常的和有问题的dump是啥样子。

通过这项技术我发现了一些通常出现在性能调优方面的误解,列出在下面。
1. NumberFormat 相当慢,尽量避免使用它。
2. String.split—不管是编码或是解码UTF8的字符串都是慢的超出你的想像— 参照上面提到的建议,使用合适的Writable类型。

3. 使用StringBuffer.append来连接字符串


测试代码:https://github.com/toddlipcon/performance-blog-code/

http://blog.cloudera.com/blog/2009/12/7-tips-for-improving-mapreduce-performance/

分享到:
评论

相关推荐

    MapReduce研究现状 .zip

    1. **数据局部性**:优化数据的分布和存储,使数据尽可能靠近处理它的节点,减少网络传输,提升效率。 2. **合理的Reducer数量**:过多或过少的Reducer都可能导致性能下降。需要根据数据量和任务需求来适当调整。 3....

    MapReduce学习笔记,亲自测试写出来的,1000分都不贵

    在部署 MapReduce 时,需要考虑以下几点: - **ResourceManager**:建议单独部署 ResourceManager,以确保其资源管理功能不受其他服务干扰。 - **NodeManager**:通常与 DataNode 部署在同一台物理机上,以提高数据...

    23、hadoop集群中yarn运行mapreduce的内存、CPU分配调度计算与优化

    优化YARN和MapReduce的内存分配时,需要考虑以下几点: - 确保配置的内存大小与实际硬件匹配,避免资源浪费。 - 根据工作负载动态调整资源配置,例如,处理大数据量的任务可能需要更多的内存和CPU。 - 监控集群性能...

    Hadoop - Mapreduce

    为了提高效率,计算节点和存储节点通常是相同的,即 MapReduce 框架和 Hadoop 分布式文件系统 (HDFS) 在同一组节点上运行。这种配置使得框架能够有效地将任务调度到数据已经存在的节点上,从而在整个集群中实现非常...

    阿里云 专有云Enterprise版 V3.5.0 E-MapReduce 开发指南 - 20190327.pdf

    7. **最佳实践**:分享来自阿里云的经验和建议,以提高效率和降低运维成本。 8. **故障排除**:列出常见问题及其解决方案,帮助用户快速解决遇到的问题。 总的来说,这份E-MapReduce开发指南旨在为用户提供全面的...

    Hadoop硬实战 [(美)霍姆斯著][电子工业出版社][2015.01]_PDF电子书下载 带书签目录 高清完整版.rar )

    5.2 通过压缩提高数据存储效率 技术点25 选择合适的压缩解码器 技术点26 在HDFS、MapReduce、Pig 和Hive 中使用数据压缩 技术点27 在MapReduce、Hive 和Pig 中处理可分割的LZOP 5.3 本章小结 6 诊断和优化...

    hadoop权威指南第四版英文原版

    8. **最佳实践**:提供关于数据处理、性能优化、安全性等方面的实用建议,帮助读者避免常见陷阱,提高Hadoop应用的效率和稳定性。 总之,《Hadoop权威指南》第四版英文原版是深入理解Hadoop及其生态系统的宝贵资源...

    Hadoop权威指南---中文版

    - **分布化**:介绍MapReduce如何实现任务的分布化处理,以及这种方式对于提高处理效率的重要性。 - **Hadoop流**:解释了Hadoop流作为一种工具,允许开发者使用脚本语言来编写MapReduce程序,而无需使用Java。 - **...

    教你如何查看API及使用hadoop新api编程 高清完整版PDF下载

    ### Hadoop新旧API对比及应用 #### 一、引言 随着Hadoop生态系统的不断发展和完善,其核心组件之一...通过深入理解Hadoop新旧API的区别,开发者可以更好地利用Hadoop的强大功能来处理大规模数据集,提高数据处理效率。

    零基础学习hadoop(编程篇).docx

    在零基础学习Hadoop编程的过程中,有几个关键知识点是必须掌握的。首先,Hadoop是一个基于Java的分布式计算框架,它允许数据在多台机器上并行处理,极大地提升了处理大数据的效率。因此,学习Hadoop编程的第一步是...

    Hadoop安装部署问题文档.rar

    在使用Ambari进行Hadoop部署时,有几点需要注意: 1. 首先确保所有服务器上都安装了Ambari服务器和Agent,且版本一致。 2. 在Ambari中定义好主机名和主机映射,以确保集群内的通信正常。 3. 在安装服务时,Ambari会...

    大数据下的典型机器学习平台综述.pdf

    《大数据下的典型机器学习平台综述》这篇文章主要探讨了在大数据环境下,...这些关键词揭示了本文的核心内容,即在大数据环境下,通过理解并行计算模型和选择合适的机器学习平台,来提升数据分析和预测的效率和准确性。

    基础学习hadoop编程篇.docx

    在编程时,注意以下几点: 1. 使用Maven管理依赖:Maven是一个项目管理工具,用于下载所需库和构建项目。对于Hadoop开发,你需要知道如何使用Maven下载Hadoop源码并进行编译。 2. 熟悉Eclipse IDE:Eclipse是常见...

    大数据基础及进阶+面试指南

    在Java项目中,以下几点尤其重要: 1. **Java编程基础**:理解Java语法、面向对象编程、异常处理和集合框架等,是进行大数据开发的前提。 2. **Java与Hadoop集成**:使用Java编写MapReduce程序,理解JobTracker和...

    大数据应用分析(Hadoop)45.pptx

    东软作为IT解决方案提供商,建议企业应考虑以下几点来利用Hadoop进行大数据应用: 1. 理解业务需求:大数据的应用必须与具体的业务场景相结合,理解并定义所需解决的问题。 2. 选择合适的Hadoop组件:根据业务需求...

    大数据技术助力小微企业经营发展的研究.zip

    综上所述,这篇研究很可能深入剖析了大数据技术如何帮助小微企业在信息爆炸的时代背景下,提升经营效率、增强竞争力,并提供了实际应用的案例和建议。对于想要了解或利用大数据技术改善小微企业经营状况的读者来说,...

    Apache HBase ™ Reference Guide

    行键设计**:提供了一些建议,帮助用户设计出有效的行键,以提高查询效率。 - **35. 版本数量**:解释了如何根据应用场景来确定存储多少个数据版本。 - **36. 支持的数据类型**:介绍了HBase支持的数据类型及其特性...

    Hadoop实战中文版.pdf

    下面将基于此标题、描述及标签,深入探讨与Hadoop相关的几个核心知识点。 ### Hadoop简介 Hadoop是一个开源软件框架,用于分布式存储和处理大型数据集。它最初由Apache Software Foundation开发,旨在为海量数据...

    分布式计算框架下的大数据机器学习.pdf

    Spark是一个分布式计算框架,它具有几个显著特点:首先,Spark通过在内存中处理数据来提高计算效率,这比传统的硬盘存储方式更快。其次,Spark对多种编程语言提供良好的支持,如Scala、Java和Python等,这使得开发...

Global site tag (gtag.js) - Google Analytics