简介
Hadoop 是一个灵活的开放源码 Java 框架,用于在一般硬件网络上执行大规模数据处理。它的思想来源于最初由 Google Labs 开发的 MapReduce 和 Global File System (GFS) 技术,由于具有高效、可靠和可伸缩的优点,它越来越流行了。Hadoop 现在是顶级 Apache 项目,IBM、Google、Yahoo! 和 Facebook 等许多公司都支持和使用 Hadoop,它已经成为大规模数据处理方面事实上的行业标准框架。
Hadoop 对于云计算意味着什么?云计算的目的之一是,以尽可能低的开销为计算机资源提供高可用性。Hadoop 能够处理数千个节点和 PB 量级的数据,可以自动地处理作业调度、部分失败和负载平衡,因此它是实现这个目标的完美工具。
要想充分使用计算机资源,优化性能是非常重要的,包括 CPU、内存和 I/O(磁盘和网络)。Hadoop 可以自动地改进性能,同时向用户提供接口,让他们可以针对自己的应用程序优化性能。本文介绍重要的 Hadoop 可配置参数以及分析和调优性能的方法。
回页首
建立环境
部署 Hadoop 环境的步骤
在执行性能调优之前,需要先构建 Hadoop 集群环境。步骤如下:
$HADOOP_HOME
代表解压位置。 $HADOOP_HOME
目录并修改配置文件。
$HADOOP_HOME/conf/masters
中。 $HADOOP_HOME/conf/slaves
中,每个主机一行。 注意:如果使用主机名,就需要通过配置 /etc/hosts
文件确保集群中的所有节点都知道每个主机名。 $HADOOP_HOME/conf/core-site.xml
中以设置 NN IP/端口:
<property> <name>fs.default.name</name> <value>hdfs://host001:9000</value> </property> |
$HADOOP_HOME/conf/mapred-site.xml
中以设置 JT IP/端口:
<property> <name> mapred.job.tracker </name> <value>host002:9001</value> </property> |
mapreduce.jobtracker.address
。$HADOOP_HOME/conf/hdfs-site.xml
中:
<property> <name>dfs.datanode.dns.nameserver</name> <value>eth1</value> <description>The name of the Network Interface from which a data node should report its IP address. </description> </property> |
$HADOOP_HOME/conf/
目录中。 $HADOOP_HOME/bin
目录。
$./hadoop namenode -format
命令格式化 NN。 start-all.sh
脚本以启动 Hadoop 守护进程。 安装并配置 nmon 性能监视工具
nmon 是一个系统管理、调优和基准测试工具,可以简便地监视大量重要的性能信息。可以在整个性能调优过程中使用 nmon 作为监视工具。按以下步骤安装并配置 nmon,建立自己的性能监视系统:
$NMON_HOME
代表放置 nmon 二进制代码的位置。 /home/hadoop/perf_share
)并通过 NFS 共享它:
$mkdir /home/hadoop/perf_share
/home/hadoop/perf_share *(rw,sync)
$/etc/rc.d/init.d/nfs restart
perf_share
目录:
$mkdir/home/hadoop/perf_share $mount host002: /home/hadoop/perf_share /home/hadoop/perf_share |
hosts=( shihc008 shihc009 shihc010 shihc011 shihc012 shihc013 shihc014 shihc015 shihc016 shihc017) # Remove all data in /home/hadoop/perf_share for host in ${hosts[@]} do ssh $host "cd /home/hadoop/perf_share;rm -rf *" done # Start nmon on all nodes for host in ${hosts[@]} do ssh $host " /usr/bin/nmon -f -m /home/hadoop/perf_share -s 30 -c 360" done |
-f
表示希望把数据保存到文件中,并不在屏幕上显示;-m
表示保存数据的位置;-s 30
表示希望每 30 秒捕捉一次数据;-c 360
表示需要 360 个数据点(即快照),总数据收集时间为 30x360 秒,即 3 小时。回页首
Hadoop 可配置参数
Hadoop 提供许多配置选项,用户和管理员可以通过它们进行集群设置和调优。core/hdfs/mapred-default.xml
中有许多变量,可以在core/hdfs/mapred-site.xml
中覆盖它们。一些变量指定系统上的文件路径,而其他变量对 Hadoop 的内部进行深入的调整。
性能调优主要有四个方面:CPU、内存、磁盘 I/O 和网络。本文介绍与这四个方面最相关的参数,您可以使用后面介绍的方法研究 *-default.xml
中的其他参数。
与 CPU 相关的参数: mapred.tasktracker.map
和 reduce.tasks.maximum
决定由任务跟踪器同时运行的 map/reduce 任务的最大数量。这两个参数与 CPU 利用率最相关。这两个参数的默认值都是 2。根据集群的具体情况适当地增加它们的值,这会提高 CPU 利用率,由此提高性能。例如,假设集群中的每个节点有 4 个 CPU,支持并发多线程,每个 CPU 有两个核;那么守护进程的总数不应该超过 4x2x2=16 个。考虑到 DN 和 TT 要占用两个,map/reduce 任务最多可以占用 14 个,所以这两个参数最合适的值是 7。
在 mapred-site.xml
中设置此参数。
与内存相关的参数: mapred.child.java.opts
这是用于 JVM 调优的主要参数。默认值是 -Xmx200m
,这给每个子任务线程分配最多 200 MB 内存。如果作业很大,可以增加这个值,但是应该确保这不会造成交换,交换会严重降低性能。
我们来研究一下这个参数如何影响总内存使用量。假设 map/reduce 任务的最大数量设置为 7,mapred.child.java.opts
保持默认值。那么,正在运行的任务的内存开销为 2x7x200 MB =2800 MB。如果每个工作者节点都有 DN 和 TT 守护进程,每个守护进程在默认情况下占用 1 GB 内存,那么分配的总内存大约为 4.8 GB。
在 mapred-site.xml
中设置此参数。
与磁盘 I/O 相关的参数: mapred.compress.map.output
、mapred.output.compress
和mapred.map.output.compression.codec
这些参数控制是否对输出进行压缩,其中 mapred.compress.map.output
用于 map 输出压缩,mapred.output.compress
用于作业输出压缩,mapred.map.output.compression.codec
用于压缩代码。这些选项在默认情况下都是禁用的。
启用输出压缩可以加快磁盘(本地/Hadoop Distributed File System (HDFS))写操作,减少数据传输的总时间(在 shuffle 和 HDFS 写阶段),但是在另一方面压缩/解压过程会增加开销。
根据个人经验,启用压缩对于使用随机键/值的操作序列是无效的。建议只在处理大量有组织的数据(尤其是自然语言数据)时启用压缩。
在 mapred-site.xml
中设置这些参数。
io.sort.mb 参数
这个参数设置用于 map 端排序的缓冲区大小,单位是 MB,默认值是 100。这个值越大,溢出到磁盘就越少,因此会减少 map 端的 I/O 时间。注意,增加这个值会导致每个 map 任务需要的内存增加。
根据个人经验,在 map 输出很大而且 map 端 I/O 很频繁的情况下,应该尝试增加这个值。
在 mapred-site.xml
中设置此参数。
io.sort.factor 参数
这个参数设置在 map/reduce 任务中同时合并的输入流(文件)数量。这个值越大,溢出到磁盘就越少,因此会减少 map/reduce 的 I/O 时间。注意,如果给每个任务分配的内存不够大,增加这个值可能会导致更多垃圾收集活动。
根据个人经验,如果出现大量溢出到磁盘,而且排序和 shuffle 阶段的 I/O 时间很高,就应该尝试增加这个值。
在 mapred-site.xml
中设置此参数。
mapred.job.reduce.input.buffer.percent 参数
这个参数设置用于在 reduce 阶段保存 map 输出的内存的百分比(相对于最大堆大小),默认值是 0。当 shuffle 结束时,内存中剩余的 map 输出必须少于这个阈值,然后 reduce 阶段才能够开始。这个值越大,磁盘上的合并就越少,因此会减少 reduce 阶段本地磁盘上的 I/O 时间。注意,如果给每个任务分配的内存不够大,增加这个值可能会导致更多垃圾收集活动。
根据个人经验,如果 map 输出很大而且在 reduce 到排序阶段本地磁盘 I/O 很频繁,应该尝试增加这个值。
在 mapred-site.xml
中设置此参数。
mapred.local.dir 和 dfs.data.dir 参数
这两个参数决定把 Hadoop 中的数据放在什么地方,mapred.local.dir
决定存储 MapReduce 中间数据( map 输出数据)的位置,dfs.data.dir
决定存储 HDFS 数据的位置。
根据个人经验,把这些位置分散在每个节点上的所有磁盘上可以实现磁盘 I/O 平衡,因此会显著改进磁盘 I/O 性能。
在 mapred-site.xml
中设置 mapred.local.dir
,在 hdfs-site.xml
中设置dfs.data.dir
。
与网络相关的参数: topology.script.file.name
这个参数指向一个用户定义的脚本,这个脚本判断机架-主机(rack-host)映射以配置机架感知。在 core-site.xml
文件中设置此参数。
机架感知是对于提高网络性能最重要的配置,强烈建议按 http://hadoop.apache.org/common/docs/current/cluster_setup.html#Hadoop+Rack+Awareness 和http://wiki.apache.org/hadoop/topology_rack_awareness_scripts 上的说明配置它。
mapred.reduce.parallel.copies 参数
这个参数决定把 map 输出复制到 reduce 所使用的线程数量,默认值是 5。增加这个值可以提高网络传输速度,加快复制 map 输出的过程,但是也会增加 CPU 使用量。
根据个人经验,增加这个值的效果不太明显,建议只在 map 输出非常大的情况下增加这个值。
注意:上面列出的参数名都是 Hadoop 0.20.x 中的;如果使用 0.21.0,名称可能有变化。除了 Hadoop 参数之外,还有一些会影响总体性能的系统参数,比如机架间带宽。
回页首
如何调优和提高性能
介绍了上面的预备知识之后,现在讨论如何调优和提高性能。可以把整个过程划分为以下步骤。
步骤 1:选择测试基准
整个 Hadoop 集群的性能由两个方面决定:HDFS I/O 性能和 MapReduce 运行时性能。Hadoop 本身提供几个基准,比如用于 HDFS I/O 测试的TestDFSIO
和 dfsthroughput
(包含在 hadoop-*-test.jar
中)、用于总体硬件测试的Sort
(包含在 hadoop-*-examples.jar
中)和 Gridmix
(它模拟网格环境中的混合工作负载,放在$HADOOP_HOME/src/benchmarks
目录中)。可以根据自己的测试需求选择任何基准。
在所有这些基准中,当输入数据很大时,Sort
可以同时反映 MapReduce 运行时性能(在 “执行排序” 过程中)和 HDFS I/O 性能(在 “把排序结果写到 HDFS” 过程中)。另外,Sort
是 Apache 推荐的硬件基准。(可以通过Hadoop Wiki 找到相关信息。)因此,本文使用Sort
作为示例测试基准讲解性能调优方法。
步骤 2:构建基线
注意:把上面提到的 start_nmon.sh
脚本和以下脚本放在存储测试结果的目录中。
baseline_test.sh
#!/bin/sh # since there are 10 nodes, should write 50 GB file on each fSize=5368709120 $HADOOP_HOME/bin/hadoop jar $HADOOP_HOME/hadoop-0.20.1-examples.jar randomwriter -D test.randomwrite.bytes_per_map=$fSize /rand_$fSize 2>&1 | tee ./testRes/randomwriter_$fSize.out mkdir -p ./testRes/nmonFiles # run three cycles to get a more precise result for runtimes in {a,b,c} do ./ run_sort_baseline.sh $fSize $runtimes done |
run_sort_baseline.sh
#!/bin/sh $HADOOP_HOME/bin/hadoop dfs -rmr /rand_$1-sorted ./start_nmon.sh $HADOOP_HOME/bin/hadoop jar $HADOOP_HOME/hadoop-0.20.1-examples.jar sort -r 70 /rand_$1 /rand_$1-sorted 2>&1 |tee ./testRes/sort_baseline_$2.out cp -r /home/hadoop/perf_share ./testRes/nmonFiles/mb$4_$2 |
mapred.tasktracker.map.tasks.maximum
= 2 (默认值) mapred.tasktracker.reduce.tasks.maximum
= 2 (默认值) mapred.reduce.parallel.copies
= 5 (默认值) mapred.child.java.opts
= -Xmx200m (默认值) mapred.job.reduce.input.buffer.percent
= 0 (默认值) io.sort.mb
= 100 (默认值) io.sort.factor
= 10 (默认值) mapred.local.dir
= /hadoop/sdb
dfs.data.dir
= /hadoop/sdc
, /hadoop/sdd
,/hadoop/sde
平均 CPU | 平均内存(活跃) | 平均磁盘 | 平均网络 (KB/s) | ||||
---|---|---|---|---|---|---|---|
磁盘读 (KB/s) | 磁盘写 (KB/s) | 每秒 IO | 读 | 写 | |||
NameNode | 0.10% | 552.43MB | 0.0 | 18.1 | 1.7 | 8.0 | 31.8 |
JobTracker | 0.30% | 822.19MB | 0.0 | 34.1 | 2.0 | 8.8 | 13.0 |
DataNode | 42.5% | 6522.32MB | 49431.2 | 37704.0 | 605.3 | 6134.9 | 7126.4 |
获得所有 nmon 数据之后,可以使用 nmonanalyser 生成图表。因为 nmonanalyser 是一个 Excel 电子表格,所以只需打开它,单击analyse nmon data,选择 nmon 文件。然后就可以得到经过分析的图表。
nmonanalyser 对于基线测试生成的详细图表如下:
步骤 3:寻找瓶颈
需要根据监视数据和图表仔细地研究系统瓶颈。因为主要的工作负载分配给 DN/TT 节点,所以应该首先观察 DN/TT 节点的资源使用量(下面只给出 DN/TT 节点的 nmon 图表以节省篇幅)。
通过研究基线监视数据和图表,可以发现系统中有几个瓶颈:在 map 阶段,没有充分使用 CPU(大多数时候不到 40%),而且磁盘 I/O 相当频繁。
步骤 4:打破瓶颈
首先尝试提高 map 阶段的 CPU 利用率。前面对 Hadoop 参数的说明指出,要想提高 CPU 利用率,需要增加 mapred.tasktracker.map
和reduce.tasks.maximum
参数的值。
在测试环境中,每个节点有两个支持并发多线程的 4 核处理器,所以有 16 个可用的位置,可以把这两个参数设置为 7。
为了完成这一修改,需要在 mapred-site.xml
中设置 mapred.tasktracker.map
和reduce.tasks.maximum
参数,重新启动集群,再次启动 baseline_test.sh
(因为在mapred-site.xml
文件中进行配置,所以这里不需要修改脚本)。修改后的 mapred-site.xml
如下所示:
<configuration> <property> <name>mapred.tasktracker.map.tasks.maximum</name> <value>7</value> </property> <property> <name>mapred.tasktracker.map.tasks.maximum</name> <value>7</value> </property> </configuration> |
下面是调优后的测试结果:
平均 CPU | 平均内存(活跃) | 平均磁盘 | 平均网络 (KB/s) | ||||
---|---|---|---|---|---|---|---|
磁盘读 (KB/s) | 磁盘写 (KB/s) | 每秒 IO | 读 | 写 | |||
NameNode | 0.10% | 520.88MB | 0.0 | 21.2 | 2.0 | 6.4 | 12.7 |
JobTracker | 0.50% | 1287.4MB | 0.0 | 22.5 | 1.6 | 6.4 | 5.1 |
DataNode | 48.4% | 12466.8MB | 51729.07 | 44060.67 | 669.9 | 7462 | 6865 |
步骤 5:新一轮调优,重复步骤 3 和 4
增加每个 TaskTracker 中 map/reduce 任务的最大数量之后,观察获取的数据和图表,可以看到在 map 阶段已经充分使用 CPU 了。但是与此同时,磁盘 I/O 频率仍然很高,所以需要新一轮调优-监视-分析过程。
需要重复这些步骤,直到系统中没有瓶颈,每种资源都充分使用为止。
注意,每次调优不一定会提高性能。如果出现性能下降,需要恢复以前的配置,尝试用其他调优措施打破瓶颈。在这次测试中,最终取得的优化结果如下:
步骤 6:可伸缩性测试和改进
为了进一步检验调优结果,需要在使用优化后的配置的情况下增加集群规模和输入数据规模,从而测试配置的可伸缩性。具体地说,把集群规模增加到 30 个节点,把输入数据规模增加到 1.5TB,然后再次执行上面的测试过程。
由于篇幅有限,这里不详细描述调优过程。监视和分析方法与上面提到的完全相同,发现的主要瓶颈出现在网络中。当输入数据增加到 TB 量级时,机架间带宽变得不足。把机架间带宽增加到 4 Gb,10 节点集群优化后的所有其他参数保持不变,最终的执行时间是 5916 秒,这相当接近 10 节点集群优化后的结果(5670 秒)。
回页首
结束语
您现在了解了如何监视 Hadoop 集群、使用监视数据分析系统瓶颈和优化性能。希望这些知识能够帮助您充分使用 Hadoop 集群,更高效地完成作业。可以使用本文描述的方法进一步研究 Hadoop 的可配置参数,寻找参数配置与不同作业特征之间的关联。
另外,这种基于参数的调优比较 “静态”,因为一套参数配置只对于一类作业是最优的。为了获得更大的灵活性,您应该研究 Hadoop 的调度算法,寻找提高 Hadoop 性能的新方法。
参考资料
学习
讨论
关于作者
Yu Li 是一位中国软件工程师。他是 IBM InfoSphere BigInsight 团队的成员,这个团队的任务是在 Apache Hadoop 上构建分析平台。他的专业领域包括云计算、性能调优、数据挖掘、数据库技术和中间件技术。