JVM(和Spark)性能优化:使用Java Mission Control (3)
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
临时记录文件可能会有多个:
XX:StartFlightRecording=name=MyRecording,settings=profile -
XX:FlightRecorderOptions=dumponexit=true,dumponexitpath=/var/tmp,defaultrecording=true,
disk=true,repository=/var/tmp,maxage=45m
- 点赞
- 收藏
- 关注作者
评论(0)