JVM(和Spark)性能优化:使用Java Mission Control (3)

举报
大数据小粉 发表于 2016/11/15 15:17:34 2016/11/15
【摘要】 JVM(和Spark)性能优化:使用Java Mission Control

3 优化Spark程序实战

JMC可以监控JVM上的多种语言,包括Scala语言,及用Scala写的sbt和Apache Spark大数据平台等。
可能大家最感兴趣的是想知道,程序中哪些地方最耗费较长的时间?哪些地方占用的内存较多?我们通过热 点(hotspot)类和热点方法,及垃圾收集情况,就能通过数据清楚地知道了。

有一种较为简单的做法。Spark平台可能是长期运行的,可在启动Spark时在其JVM选项里加上【命 令2】,然后通过【命令3】开始一个记录,接着运行你的Spark程序。命令3中的duration参数要注意, 要大于你的Spark程序运行时间。运行完后你就可通过【命令4】转储出记录文件,复制这个文件到客户 端,最后用JMC打开此文件分析即可。下面就是我的操作命令(蓝色字体)的过程:

D:\study\spark-workshop>jps
17636
11656 Jps
3584 Boot
13364 SparkStreaming8Main
D:\study\spark-workshop>jcmd 13364 JFR.start name=MyRecording settings=profile delay=10s duration=60s
13364:
Recording 7 scheduled to start in 10 s.
Use JFR.stop name=MyRecording filename=FILEPATH to copy recording data to file.
D:\study\spark-workshop>jcmd 13364 JFR.check
13364:
Recording: recording=0 name="HotSpot default" (running)
Recording: recording=7 name="MyRecording" duration=1m (stopped)
D:\study\spark-workshop>jcmd 13364 JFR.dump name=MyRecording filename=myrecording.jfr
13364:
Dumped recording "MyRecording", 2.4 MB written to:
D:\study\spark-workshop\myrecording.jfr
D:\study\spark-workshop>

这样你就可以在一个Spark应用程序运行前开始记录,运行完后再dump出记录文件,这是一个loop 。下一个/下一次Spark应用程序运行,按此loop,不断的评估改进效果。

下图就显示出“代码”->“热点方法”,Spark程序WordCount2SortByWord中调用的Java String.split方法最耗时。你还可以一层层展开,它是被哪个方法调用的。

“代码”->“调用树”,也可以一层层展开调用关系,例如从WordCount2SortByWord.main开始, 调用了SparkContex,RDD等类的一些方法。

从下图可以看出,在SparkStreaming8Main这个程序中,最耗时的热点方法
是org.apache.spark.util.collection.AppendOnlyMap.changeValue(Object, Function2):

3.1 在Linux/Spark开发测试环境中启用JFR

通常在较正式的开发测试环境下,有数十个节点运行Spark应用程序。需要在每个节点,包括Driver和 Executor的JVM上都要加上相关选项。可以统一加在spark-env.sh (可能
在/opt/tsp/server/hadoopclient/Spark/spark/conf/ )文件中,自动分发到各个节点。

SPARK_JAVA_OPTS="$SPARK_JAVA_OPTS -XX:+UnlockCommercialFeatures"
SPARK_JAVA_OPTS="$SPARK_JAVA_OPTS -XX:+FlightRecorder"
SPARK_JAVA_OPTS="$SPARK_JAVA_OPTS -XX:StartFlightRecording=name=MyRecording,settings=profile"
SPARK_JAVA_OPTS="$SPARK_JAVA_OPTS -XX:FlightRecorderOptions=dumponexit=true,dumponexi
tpath=/var/tmp,defaultrecording=true,disk=true,repository=/var/tmp,maxage=45m"

以上【命令选项5】的作用是在在应用程序启动时,启动默认的记录,当应用程序完成时,自动生成记 录文件到目录/var/tmp下。repository指定的是临时记录文件的位置,默认在java.io.tmpdir。settings=profile是为了比 default多记录一些事件。maxage=45m(默认为15分钟),把这个延长,能收集更多的数据,发现更多东西。This is a very powerful way of ensuring that data always exists for at least some time leading up to a problem.还有个类似参 数maxsize,允许记录文件的最大大小,你可以把它设置为100MB:maxsize=100m。 参见:。
http://docs.oracle.com/cd/E15289_01/doc.40/e15070/usingjfr.htm

你应该可以在Spark UI上看到这些JVM选项。然后就可以通过脚本把各个节点上的所有jfr文件复制到 某个机器上。

例如,以下getdump.sh文件可以把上图中各机器上自动生成的记录文件复制到一个机器,其中在文件名前加 上了主机名以便区别是哪个节点生成的。

#!/bin/bash
hosts=`cat /etc/hosts | grep SR | awk '{print $2}'`
mkdir -p jfrfiles
for host in $hosts
do
scp $host:/var/tmp/*.jfr ./jfrfiles/
cd ./jfrfiles/
files=`ls 2015*.jfr`
for file in $files
do
mv $file "$host."$file
} done
cd -
} done

在实际Spark环境下,常常会在/var/tmp目录下累积生成多个jfr记录文件,想找自己某次运行的jfr只能 靠文件名的时间戳来识别。可以写个清理脚本先把/var/tmp下的jfr文件都移走(例如到jfr_bak目录)或删 除它们,然后再运行应用程序,这样最新生成的jfr就是你的了。也可以把这个清理脚本放到Spark启动脚本 前调用之。

临时记录文件可能会有多个:

这也可以改到其它目录,例如repository=/var/log目录下。这目录下的文件可以通过一个命令来合并成 更大的jfr文件。例如:

cd /var/tmp/
/opt/huawei/Bigdata/jdk1.7.0_72/bin/java oracle.jrockit.jfr.tools.ConCatRepository
/var/tmp/2015_02_08_19_15_51_216493 -o 2015_02_08_19_15_51.jfr

临时记录文件可能会有多个:


mapred.child.java.opts
-XX:+UnlockCommercialFeatures -XX:+FlightRecorder -
XX:StartFlightRecording=name=MyRecording,settings=profile -
XX:FlightRecorderOptions=dumponexit=true,dumponexitpath=/var/tmp,defaultrecording=true,
disk=true,repository=/var/tmp,maxage=45m

作者 | 孙奇辉

转载请注明出处:华为云博客 https://portal.hwclouds.com/blogs

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。