HPUX中的Java应用性能调优概述Word格式文档下载.docx
《HPUX中的Java应用性能调优概述Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《HPUX中的Java应用性能调优概述Word格式文档下载.docx(37页珍藏版)》请在冰豆网上搜索。
采用系统化的方法
Java性能分析中存在许多的不确定因素。
HP-UX内核参数、在运行时指定的JVM选项以及应用设计等所有一切都会带来相应的影响。
正是由于该原因,所以在分析性能问题时应采取从上至下系统化的方法(从最外层的系统角度)并在首次分析时考虑所有的可能性,这一点非常重要。
采取从上至下的方法,我们首先将系统作为一个整体来考虑(将一台或多台协作的计算机作为一个集合,它们互相之间具有网络影响,可能在某些点还存在数据库访问影响)。
在考虑了整个系统中所有的可变因素之后,我们将分析范围缩小到单个计算机,再进一步缩小到该计算机中的单个进程,从而找出问题的根本原因。
之所以采用从上之下的分析方法,是因为导致性能问题的原因可能存在于程序、计算机、数据源和网络等构成整个系统的各个部分。
有多种工具可以帮助我们逐一分析每台计算机,HP-UXGlance/gpm便是其中最强大的工具之一,本文后面的部分会再次提到该工具。
过去,研发实验室进行的分析工作发现性能瓶颈的原因也可能源于非Java的技术。
性能工程师必须时刻考虑到这一点。
系统中各台计算机之间以及计算机与其外部数据源之间的数据交换也必须进行检查。
这项工作可以通过使用“netstat”等网络与数据库监视工具来完成。
推荐流程中的步骤包括:
●评估整体的系统配置、吞吐量和负载情况;
●测量性能(使用我们将进一步详细介绍的工具);
●分析来自性能测量工具的数据;
●确定一个或多个可能的瓶颈;
●每次仅更改或调节一个项目;
●再次测量性能以检查该调节步骤所带来的变化。
在本文以后的章节我们将会更加详细地分析这些步骤。
在分析过程中考虑来自多个工具的数据并反复核对其输出结果也非常重要。
例如,Glance/gpm生成的线程信息应该与将“kill–3<
”命令应用于JVM进程时所看到的线程数据一致。
较高的吞吐量水平并非总是性能问题的原因所在。
许多生产系统在运行时都一直保持高容量的交易流。
性能工程师所要面对的真正问题是“进程中的瓶颈在哪里,并且它们如何被触发?
”
为了找出这些瓶颈,有时候需要为系统添加负载,再现峰值用户处理水平时的负载,这时候系统将非常繁忙。
有多种工具可以在基于Web的应用上实现这种高负载,它们将在本文最后的工具章节中介绍。
避免在信息不充分的情况下妄加猜测
不经过分析和测量便对问题原因作出最初的猜测非常具有诱惑力,特别是在项目小组承受着压力要解决一个问题时。
这种情况应该避免。
通常情况下,我们所作的猜测会造成误导。
相反,我们建议先使用各种工具(Glance/gpm、Hpjmeter、Hpjtune、sar、–Xverbosegc和–Xeprof的JVM选项等等)来收集性能数据,在这些工具的数据经过分析并被了解之后,便可以就所见的症状给出原因了。
该分析需要一定的时间,通常性能工程师进行性能调优的第一步是先搜集系统运行数据,而不是上来就修改系统参数。
准备一个修改记录非常重要,用于记录所作出的每一个变更,以及应用变更后所带来的性能影响。
性能工程师非常容易对系统一次进行多个变更,这种情况应该避免。
因为多个变更、多种结果以及许多的外部影响因素很容易给工程师造成混乱,所以应该以书面的形式将所应用的变更记录下来。
测试大型应用具有代表性的较小样本
计算机编程中的一个常用故障排除技巧是将问题尽可能分解到能够反映症状的最小代码块。
但是这种方法在性能分析中却非常危险,因为较小样本的行为通常与实际生产系统有很大差别。
建议尽可能在“真实的”系统上进行性能分析,而不是采用大型系统的子集。
这可能会占用测试的时间,但是所获得结果的将会更加准确。
在分析一个系统时,测量工具本身确实也会对性能产生影响。
例如Glance/gpm便是HP-UX系统中的一个进程,它会占用该机器的一部分CPU资源。
我们所使用的工具已经尽可能使这种影响将到最低。
但我们在使用一个测量工具时,这种影响总是存在的。
将系统作为一个整体进行评估
当前许多基于web的体系结构可能采用一组计算机作为web服务器层,另一组计算机作为应用服务器层以及一个数据库层。
所有这些都通过网络连在一起,并互相作用以响应每一个客户请求(例如通过浏览器发出的请求)。
进行整体系统评估的主要工具有Glance/gpm(图形进程监视)以及类似的工具(如HPPerfView),它能够显示单个计算机中操作系统和进程的状态。
Glance/gpm将就计算机不同组件的状态为工程师提供一个可视、直观的评估,例如其CPU负载、输入输出负载、网络流量,以及内存消耗率等。
在每台HP-UX计算机上使用Glance/gpm工具使工程师能够清楚地看到参与整个系统的所有机器中哪些负载紧张,哪些比较空闲。
下图显示了Glance/gpm窗口中最顶层的计算机视图,我们可以看到该计算机的“系统时间”消耗水平非常高,而被使用的“用户时间”水平非常低。
这表明该计算机存在问题。
实际上我们希望有更高的CPU消耗被用于“用户时间”(用于执行应用的时间),而不是“系统时间”(用于执行操作系统功能的CPU时间)。
机器中出现这种非常高的“系统时间”占用率可能是由于操作系统调用,它们负责锁定被称为“mutexes”的数据结构,占用很长的系统时间来解决争夺,或者等待访问这些结构的线程被强制进入休眠状态。
因此以下的情况可能是Java程序中的线程锁争夺所引起的,该话题将在本文以后的部分深入讨论。
到目前为止,我们已经知道太多的时间被用于执行系统代码,而不是应用代码。
下一步是检查机器中的哪一个特定进程造成了这种情况。
图1:
HP-UX中Glance/gpm工具的主窗口
Glance主窗口—高系统时间举例
低用户CPU时间
高系统CPU时间
从整体系统视图缩小至单个计算机,再进一步缩小至特定的进程是使用Glance/gpm工具以及其它HP-UX性能分析工具的一个练习。
它们将在参考1[Sauers]中详细描述。
数据收集
性能分析的第一个步骤是记下用户交易执行路径中每一台计算机的机器设置(从而找出怀疑对象)。
我们需要的信息包括:
●计算机中CPU的数量以及这些CPU的速度(CPU的数量可以中Glance/gpm中看到)
●物理内存的大小(也可以在Glance/gpm中看到)
●磁盘空间的大小(已占用和可用的容量,在“df”命令的输出结果中)
●操作系统可调节参数的值(使用Hpjconfig工具可以看到)
●需要的操作系统补丁(Hpjconfig也能提供帮助)
●使用的JVM版本(使用“java–version”命令可以找到)
●使用的JVM选项(如–Xms<
value>
、-Xmx<
或其它)。
以下表1中是“java–version”命令所输出的Java版本信息的举例。
Javaversion"
1.3.1.00-release"
Java(TM)2RuntimeEnvironment,StandardEdition(build1.3.1.00-release-010607-16:
53-PA_RISC1.1)
JavaHotSpot(TM)ServerVM(build1.3.11.3.1.00-release-010607-19:
35-PA_RISC2.0PA2.0,mixedmode)
表1.“Java–version”命令输出的Java运行时版本信息
以上的每一个值均能帮助性能工程师测量机器中Java程序的性能特征。
只需简单地升级至最新的JavaSDK版本,升级操作系统并应用最新的补丁,或者使用Java运行时的正确选项,便能够解决一部分性能问题了。
建议性能工程师先升级至最新的JavaSDK版本和最新的补丁,以证明这样是否能够改善系统的状况。
下一章(“hp-ux内核参数”)中描述的Hpjconfig工具也能够检查是否已经应用了正确的HP-UX补丁。
表2显示了Java虚拟机的一种误用情况。
该实例显示了用户使用了较旧、未经优化的Java运行版本(“classicJVM”),它不适合用于服务器端长期运行的应用。
建议在这种情况下使用默认的Java运行(“HotSpotJVM”)。
$java–classicClassName
表2.使用较旧、低效的Java运行时版本—这种情况应该避免。
hp-ux内核参数
对操作系统进行正确的设置,使其以最优的方式来运行Java程序极其重要。
几个HP-UX可调参数会影响这一正确的设置。
用于确定这些可调参数最佳值的工具是Hpjconfig,它本身也是一个Java程序。
Hpjconfig是一个免费的程序,可以从以下网址下载
表3显示了Hpjconfig的调用。
$java–cpHPjconfig.jar:
HPjconfig_data.jarHPjconfig
表3.使用Hpjconfig工具
该工具首先检查运行其的计算机的型号,然后允许性能工程师来选择各种不同的应用类型,例如“应用服务器”、“Web服务器”和“WAP服务器”等。
随后它将就某些HP-UX内核可调参数应该采用的值提出合理的建议。
它还能够将输出结果数据保存在一个文件中。
然后系统管理员便可以使用SAM系统管理工具将这些推荐的值应用到操作系统中。
图2显示了Hpjconfig的初始界面。
此时,工具正在检查应用到当前HP-UX系统中的补丁是否适合于Java。
性能分析流程
Hpjconfig:
检查补丁
图2:
HP-UX系统中Hpjconfig工具的主界面
图3显示了针对特定应用类型所推荐的内核参数举例,如Hpjconfig工具中所见。
内核参数
更新至推荐的值
图3:
Hpjconfig工具的HP-UX内核参数窗口
了解有关这些参数进一步的详细信息,请访问中国惠普公司技术动力社区并在技术论上进行交流:
http:
//210.82.87.227/partnerportal/solutioncommunity.aspx
请注意Hpjconfig窗口“推荐的调整值”一列中所显示的值仅仅是一些建议。
如果一台计算机上运行了多个应用进程或数据库进程,那么HP-UX内核可调参数的最优值将需要在Java程序以及共享这台机器的其它程序之间实现平衡。
对Java程序最为重要的具体HP-UX内核可调参数包括:
●max_thread_proc—决定任何单个进程中所允许的最大线程数量;
●maxdsiz—决定任何进程的数据段大小;
●maxfiles—为任何进程能够打开的最大文件数量指定一个软限制;
●maxfiles_lim—为任何进程能够打开的最大文件数量指定一个硬限制;
●ncallout—决定I/O等待的最大超时值;
●nfile—决定计算机系统中所能打开的最大文件数量;
●nkthread—决定计算机系统支持的最大内核线程数量;
●nproc—指定计算机系统中所允许的最大进程数量
垃圾回收
Java程序需要一定的对象,它们运行时将会占用部分内存。
这些对象可能在程序开始运行时创建,也可能在程序运行过程中创建。
在创建一个新的Java语言对象时,分配给它的内存将被放置在一个被称为“heap”的区域。
该heap内存的大小是有限制的。
对于任何JVM运行其默认最大值被设定为128MB,除非用户使用JVM选项–mx或–Xmx调整了最大值。
以下命令将以默认的heap大小值来运行JVM(未指定选项)。
$javaClassName
(ClassName是该应用的开始类)
表4.以默认的128Mb最大heap值运行Java
以下命令限制该第二个JVM运行至多占用240MB的heap大小。
$java–Xmx240mClassName
表5.带有240Mb最大heap值的Java运行
在第二个程序试图为对象分配内存(创建新的对象)时,如果对象需要占用超过240Mb的内存,那么JVM将会产生一个异常信息“OutOfMemoryException”,程序的执行便会终止。
Java程序与C或C++程序不同,它不会显式地重新分配或释放占用的heap内存(而C/C++程序器会使用“delete”运算符来释放内存)。
这是由JVM本身来完成的,而不是程序。
JVM通过确保程序的任何部分都不再引用该对象,从而检测到程序已经不再使用该对象。
清除不再使用的对象被称为“垃圾回收”,它可以被视为JVM运行间隔期间的一种分离、独立的活动。
这些间隔由多种因素决定,其中之一便是要求更多的heap空间。
该内存管理策略的影响是一旦决定JVM的垃圾回收应该开始,执行Java字节代码的所有其它线程,无论是解释或编译的形式,在垃圾回收过程期间都必须返回至安全点并停止。
如果该过程持续较长的时间,那么它便会给Java程序的性能造成严重影响。
由于这个原因,在分析Java程序的性能时,分析垃圾回收的行为总是非常重要。
图4显示了单个JVM在一台8CPU的计算机上执行的过程中,垃圾回收活动发生时的瞬间影响。
可以看到,只有一个CPU正在执行有用的工作,即垃圾回收器本身。
其它的CPU几乎未被使用。
Glance屏幕—垃圾回收的影响
图4:
在运行HP-UX的8CPU系统上,Glance/gpm工具的CPU屏幕中看到的垃圾回收
因此过多的垃圾回收活动是造成Java程序缓慢的重要原因,所以必须通过评估和更改影响heap的JVM选项来进行调整,选项包括-Xms、-Xmx、-Xmn和–XX:
SurvivorRatio。
但是,第一步是检查JVM的垃圾回收部分是否发生了过多的活动。
在Glance/gpm的主窗口中我们可以获得很好的线索,来判断垃圾回收活动是否频繁。
如下图5所示“尖峰”状的CPU行为类型能够表明出现了我们不希望的垃圾回收活动。
图5表明用户程序时间在垃圾回收器接管CPU后经历了非常大的下跌。
Glance—频繁的垃圾回收
图5:
HP-UXGlance/gpm工具中“尖峰”状的CPU行为类型
由于我们拥有JVM的“-Xverbosegc”选项,这一检测工作可以通过HP-UX上的Java轻松实现,该选项的使用方式如下。
$java–Xverbosegc:
file=myfile.outClassName
表6.利用-Xverbosegc运行Java
这使JVM能够在文件“myfile.out”(文件名仅仅是这里的举例)中生成详细的垃圾回收器数据。
注:
该选项在运行时对JVM只有非常低的影响(除了向磁盘写入输出数据造成的影响),所以必要时可以在生产应用上使用。
输出数据(在上例所说的“myfile.out”文件中)很难读懂,因为其原始格式如下:
<
GC:
-121.04056018241133691440133693440170393617039360
1206120503316484793888479388849807360.124737>
-124.040994280113369344013369344170393617039361703936
12061205058264503316485032840503284052428801.896397>
228.6027081216111093520133693441703936017039365058264
6780520503316485242688524268852428800.870284>
-145.50054936563213369136013369344080525617039366780520
6780520503316488720800872080089169920.055405>
表7.JVM“–Xverbosegc”选项的输出结果
该输出文件中有19列数据,描述了垃圾回收器heap消耗期间的各个时间和区域。
针对该输出文件,推荐下载HPjtuneGUI工具(
并应用如下的命令:
$catmyfile.out|awk–fprocessVerboseGC.awk>
output.txt
表8.在包含–Xverbosegc输出的文件上运行
processVerboseGC.awk脚本
该命令能够生成非常用户友好的输出文件,示例如下表9所示:
FullGCrequired-reason:
Oldgenerationexpandedonlastscavenge
Full1.985317ssincelast:
1.985317sgctime:
96mseden:
1834928->
0/3670016survivor:
120576->
0/262144tenure:
2old:
3204992->
2356088/3928064
Scav2.190710ssincelast:
0.205393sgctime:
4mseden:
3669968->
0->
120720/262144tenure:
32old:
2356088->
表9.在–Xverbosegc输出文件上运行
processVerboseGC122.awk脚本后的输出结果
在免费下载的HPjtune工具中查看GC数据能够获得对垃圾回收器行为的图形化视图。
这是该情形下推荐使用的方法。
以上数据描述了程序执行过程中按顺序连续发生的3次垃圾回收事件。
每次事件发生的时间,从程序开始时间算起,以秒为单位显示在“Full”或“Scav”之后。
即使在了解“eden”、“survivor”、“tenure”和“old”等术语的含义(将会在下文中解释)之前,我们也能够从以上数据中获得许多信息。
首先,1次“Full”垃圾回收(GC)事件所占用的时间要比“Scavenge”或“Scav”垃圾回收更多。
如果我们看到很多的“FullGC”条目,例如每分钟一次甚至更多,那么我们便需要采取一些措施。
如果在数据中看到一个条目包含以下内容:
“FullGCrequired–reason:
calltoSystem.gc()orRuntime.gc()”
那么我们便知道是用户的Java代码或应用使用的一些库或基础设施代码正在显式调用垃圾回收器。
这种情况永远都不应该发生。
要解决该问题,我们可以将“calltoSystem.gc()orRuntime.gc()”从代码中移除,或者使用JVM选项–XX:
+DisableExplicitGC来禁止它,如下所示:
$java–XX:
+DisableExplicitGCClassName
表10.通过禁止显式调用垃圾回收器的选项运行Java
第二,我们在“Full”或“Scav”字符串之后便可以看到从程序启动开始计算的时间。
该时间(以秒为单位)累计程序运行的时间,使我们能够了解到事件发生时程序执行的进度。
“sincelast”字符串之后是与上一次GC活动相隔的时间。
“gctime”字符串表明了该特定的GC事件完成所用的时间。
我们应特别注意这些最后的数字。
一般来说,正常JVM执行FullGC的次数要少于ScavengeGC。
ScavengeGC之间的间隔应该在5秒左右或更长,并且完成的时间不应超过300-400毫秒。
如果ScavengeGC完成的时间达到1分钟甚至更长,那么我们便知道程序暂停了那些执行Java字节代码的线程至少1分钟,出现了性能问题。
我们应该考虑调整控制heap内存使用的JVM选项来解决该问题。
这可以通过更改与JVM选项–Xms、-Xmx和–Xmn相关的值来实现,如下所述。
一旦了解到heap内存的哪些区域正被过度使用或未被充分利用,那么我们便可以更改这些值。
这将会在下一章中讨论。
FullGC可能需要1分钟甚至更长的时间,取决于需要执行回收的heap空间的大小。
一般来说,好的实践是对JVM运行进行配置,使FullGC能够在1分钟甚至更短的时间内完成,并且相对于ScavengeGC发生的次数更少。
每5至10分钟发生一次FullGC,每次持续10秒或更少,以及每隔5-10秒发生一次较小