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

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

3.2 真实的业务案例

在一般信息-JVM信息-Java应用程序参数中可以看到Spark的执行器后端,executor id为4、主机为SR2S1、分配的cores、workerUrl:

org.apache.spark.executor.CoarseGrainedExecutorBackend akka.tcp://sparkDriver@SR1S3:23718/user/CoarseGrainedScheduler 4 SR2S1 24 application_1422534342886_0019

转储出的jfr文件可能较大,超过100M,如果出现这个问题,需要加大jmc.ini的内存:

-startup
../lib/missioncontrol/plugins/org.eclipse.equinox.launcher_1.3.0.v20120522-1813.jar
--launcher.library
../lib/missioncontrol/plugins/org.eclipse.equinox.launcher.win32.win32.x86_1.1.200.v20120913-144807
-vm
./javaw.exe
-vmargs
-XX:+UseG1GC
-Xmx1024m
-Xms1024m
-XX:+UnlockCommercialFeatures
-XX:+FlightRecorder
-Djava.net.preferIPv4Stack=true


3.2.1 热点方法

无线OSS开发部是公司大规模使用Spark较早的团队,用于手机用户数据流量等的分析。在后来的开发过程中也使用JMC来度量应用程序性能瓶颈。
例如,通过JMC的代码->热点方法,高海涛发现解析的时候read4ByteLong和read8ByteLong占用时间时间很长,代码实现可以优化:

堆栈跟踪 样本计数 百分比(%)
java.lang.Integer.toString(int) 1,237 2.574
java.lang.String.valueOf(int) 1,237 2.574
com.huawei.pai.parser.WlbinInputStream.byte4ToLong(byte[], int) 649 1.351
com.huawei.pai.parser.WlbinInputStream.read4ByteLong() 649 1.351
com.huawei.pai.parser.ugwufdr.ufdrassociate2.ufdr.Parser_Struct_VOLUME.parse(WlbinInputStream, int) 422 0.878
com.huawei.pai.parser.ugwufdr.ufdrassociate2.ufdr.Parser_TLVGroup_UFDR_UFDR.parse(WlbinInputStream, int, Parser_UFDR) 422 0.878
com.huawei.pai.parser.ugwufdr.ufdrassociate2.ufdr.Parser_UFDR.parse(WlbinInputStream, int) 422 0.878
com.huawei.pai.parser.ugwufdr.ufdrassociate2.Parser_UGWUFDR_Union.parse(WlbinInputStream, int, int) 422 0.878
com.huawei.pai.parser.ugwufdr.ufdrassociate2.Parser_Struct_UGWUFDR_Log.parse(WlbinInputStream, int, int) 422 0.878
com.huawei.pai.parser.ugwufdr.ufdrassociate2.Parser_UGWUFDR.parse(WlbinInputStream) 422 0.878
com.huawei.pai.parser.ugwufdr.ufdrassociate2.Parser_Root.parse(WlbinInputStream) 422 0.878
com.huawei.pai.parser.ugwufdr.ufdrassociate2.Parser_Root_Adapter.parseToAdapters(WlbinInputStream) 422 0.878
com.huawei.pai.parser.adapter.WlbinUfdrRecordReaderAdapter.parsePkg(String, byte[], int) 422 0.878
com.huawei.pai.parser.adapter.WlbinAbstractRecordReaderAdapter.nextKeyValue() 422 0.878
com.swimap.prs.paiplugin.common.io.input.SequenceFileReaderBase.tryCacheNext() 422 0.878
com.swimap.prs.paiplugin.common.io.input.SequenceFileReaderBase$$anon$1.hasNext() 422 0.878
com.huawei.pai.parser.ugwufdr.ufdrassociate2.ufdr.Parser_Struct_TIME.parse(WlbinInputStream, int) 160 0.333
com.huawei.pai.parser.ugwufdr.ufdrassociate2.ufdr.Parser_UFDR.parse(WlbinInputStream, int) 67 0.139
com.huawei.pai.parser.WlbinInputStream.byte8ToLong(byte[], int) 588 1.224

高海涛还发现,类APP_BLOCKCAUSE_SUBS_Key的compareTo调用次数多,这两个字段(base_imsi和base_msisdn)都参与比较了,base_msisdn应该可以省略。Key对象的compareTo是系统中掉用次数最多的方法。所有Key对象的compareTo函数中,最后一个属性如果是数值类型,应该用减法,比较操作和减法操作的代价是相同的,改为减法后代价从2变成1。如果是字符串类型只应该调用一次属性的compareTo方法。


if (this.uli_flag < that.uli_flag) {
return -1;
} else if (this.uli_flag > that.uli_flag) {
return 1;
}
return 0;

可修改成 :this.uli_flag - that.uli_flag
发现一个问题,我们代码中所有Key对象重载过的hashCode方法被删除了。
我觉得这里不应该删除。每个Key对象的hashCode在reduce阶段会被调用多次,我们在这个方法上做过性能优化。

之前做过的优化:
1. 可配置哪些字段计算hashCode。我们重载的方法比默认的(使用所有字段计算)计算速度更快。
2. 存储计算过的hashCode值,Key对象的hashCode只计算一次,可使用多次。因为每次hashCode的计算需要多次乘法和加法操作,若只执行一次可显著减少执行时间。

我们内部存储对象使用的是TreeMap,TreeMap是个二叉树结构,每个对象put到TreeMap时都会多次调用compareTo方法,我们可以在compareTo方法上可以做进一步的优化。很多Key对象的字段较多,或有比较操作代价较大的字段(如String类型),这些类尤其需要优化。方法:建议所有Key存储一个hashCode值(只需计算一次),hashCode作为第一个字段参与compareTo计算,因绝大部分对象的hashCode值不同,这样绝大部分compareTo操作在第一个条件判断就返回,可显著减少计算量。

作者 | 孙奇辉

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

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

评论(0

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

全部回复

上滑加载中

设置昵称

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

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

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