两个关于JAVA性能优化的PPT
Tools and Tips to Diagnose Performance Issues
分析性能问题的一些工具和建议
Use JMeter as a Performance Testing Tool
性能检测工具——Jmeter介绍
Tools and Tips to Diagnose Performance Issues
分析性能问题的一些工具和建议
Use JMeter as a Performance Testing Tool
性能检测工具——Jmeter介绍
Java性能的优化一直是程序员关注的话题,但是论坛上此类的文章不多,IBM的developertworks上有一些关于性能优化的优秀文章,但又往往不适合你遇见的情况。这里总结了一下专门出现在性能优化文章后的推荐阅读,如果你没时间阅读《深入Java虚拟机》,那么希望这些能让你找到问题的本质。
http://java.sun.com/docs/performance
http://java.sun.com/performance/reference/whitepapers/6_performance.html
http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html
http://java.sun.com/performance/reference/whitepapers/tuning.html
http://java.sun.com/docs/hotspot/gc1.4.2/faq.html
当然我也会继续照搬这些文档中的资料,结合工具来介绍WebSphere下的性能检测与优化。其实WebSphere、Weblogic、Tomcat、jBoss,最终优化的方法殊途同归,因为都逃不出Java虚拟机这个框框。
WebSphere优化中不得不提的是对JVM的优化,OutOfMemory、GC时间太长太频繁、内存碎片、大对象问题……虽说JVM运行效率如何很大程度是和代码有关,但是恰当的参数设置还是可以避免很多问题。因为在JAVA程序中,垃圾回收(Garbage Collection——GC)是内存发生瓶颈的主要因素(在程序没有问题的情况下)。
但是JVM的优化(也就是优化GC)是一个很令人头疼的活。调整JVM需要根据不同的平台分别对待,如果不了解直接Google一个参数加上无法生效事小,适得其反就不好了。在 Sun ™Solaris™ 和 HP-UX 平台上,WebSphere使用的是Sun和HP提供的JDK,而所有其他平台,WebSphere提供的是IBM JDK。所以优化参数主要区别在IBM JDK和非IBM JDK上,Sun和Hp环境下的优化方案基本能共享。
GC优化的关键是降低频率(frequency)和减少持续时间(duration)。但是两者此消彼长,所以平衡一个恰当的值十分关键。频率和堆的大小和分配增长速度有关,而持续时间则和堆大小和堆中对象的多少有关。由此可以看出最先要考虑的就是堆的大小。
最大堆、最小堆设置:现在32位的堆,一般设置为256~512M或者512~1024M,但是
对于不同的应用程序,最优化堆大小的设置都有可能不同。如果堆设置较大,可能导致 GC 的次数变少,但每次 GC 所花的时间很长,从而导致系统的处理能力抖动很大。此外如果堆设置过大,会占用过多的内存,使内存资源耗尽,从而会频繁的进行 IO 操作来使用虚拟内存。 如果堆设置较小,可能导致 GC 变的频繁,但每次 GC 所花的时间不会太长,每次 GC 对系统的性能影响相对也会小些。但是如果堆设置过小, 会使得对象可分配空间变小,从而会频繁的 GC 来释放内存空间,而每次 GC,都会耗用一定的系统资源。因此,要通过试验和监控数据,设法使的我们所设置的堆大小能够使得系统运行最优化。
具体合适的值,可以启用-verbose:gc来观察。一般良好的堆大小,要让回收频率保持在10秒左右,而一次的full gc回收时间在1到2秒之内(一般的回收时间更短才好)。要注意的是,对于32位的JDK,在Windows环境下单个堆不要超过1.7G,AIX平台不要超过3.2G。下面摘自 出色的“清洁工具” ― 理解 IBM Java 垃圾收集器,第一部分:: 对象分配
| 问题 | 建议措施 |
| 在堆达到稳定状态以前,GC 的频率太高。 | 使用 verbosegc 确定处于稳定状态的堆大小并将 -Xms 设置成这个值。 |
| 堆被完全扩展并且占用率大于 70%。 | 增加 -Xmx 值使堆占用率不超过 70%。为了获取最佳性能,尝试确保堆从不换页。物理内存应该能容纳最大的堆大小(如果可能)。 |
| 占用率为 70% 时,GC 的频率过大。 | 更改 -Xminf 的设置。缺省值是 0.3,它将通过扩充堆来尝试维持 30% 可用空间。设置为 0.4 将可用空间目标增加到 40%,从而降低 GC 的频率。 |
| 暂停时间过长。 | 尝试使用 -Xgcpolicy:optavgpause (在 1.3.1 中引入),它在堆占用增加时减少暂停时间并且使它们更一致。在吞吐量方面要付出代价。代价是变化的,大约在 5% 左右。 |
确定了堆大小,接下来要考虑的是
IBM JDK(1.5)下WebSphere首先要了解的是4个Policy:
IBM SDK 5.0 中的 GC 策略
针对吞吐量进行优化
-Xgcpolicy:optthruput(可选)
默认策略。对于吞吐量比短暂的 GC 停顿更重要的应用程序,通常使用这种策略。每当进行垃圾收集时,应用程序都会停顿。针对停顿时间进行优化
-Xgcpolicy:optavgpause
通过并发地执行一部分垃圾收集,在高吞吐量和短 GC 停顿之间进行折中。应用程序停顿的时间更短。分代并发
-Xgcpolicy:gencon
以不同方式处理短期存活的对象和长期存活的对象。采用这种策略时,具有许多短期存活对象的应用程序会表现出更短的停顿时间,同时仍然产生很好的吞吐量。子池 (一般平台用不到)
-Xgcpolicy:subpool
采用与默认策略相似的算法,但是采用一种比较适合多处理器计算机的分配策略。建议对于有 16 个或更多处理器的 SMP 计算机使用这种策略。这种策略只能在 IBM pSeries® 和 zSeries® 平台上使用。需要扩展到大型计算机上的应用程序可以从这种策略中受益。
其中optthruput是默认的IBM JDK GC策略,我觉得不是很适合一般电子商务的情况。因为它的GC停顿时间是三种策略里最长的,而且对于频繁分配短生命周期、小对象的应用来说,很容易就产生了内存碎片,虽然标志-扫描-紧凑排列(mark-sweep-compact)的第三个阶段“紧凑排列”可以消除碎片,但是这种动作开销很大。一般需要设置P cluster、K cluster参数来减少碎片Avoiding Java heap fragmentation with Java SDK V1.4.2. (这个参数在1.5中也适用)
optavgpause是以一点吞吐量的牺牲(官方说是5%)换来响应时间的提高,用并发标记(JDK1.4)外加并发扫描(JDK1.5引入)的方式来减少GC “Stop the world”的时间。
但一般而言,我都是设置成-Xgcpolicy:gencon ,gencon就是我们常说的“分代回收”策略,在HP和SUN的JDK实现中是默认的回收策略。这篇文章Java 理论与实践: JVM 1.4.1 中的垃圾收集,介绍的就是分代回收策略,而且肯定是针对SUN的JDK,当然HP的也适用。可以关注下面这张图:
形象直观,文章里的文字总忘掉七零八落,但那些原理可以日后巩固,这幅图保存好了设置参数就没啥大问题。
注意下图显示的IBM JDK的分代回收参数设置和SUN/HP的不同
IBM没有设置MaxPermSize的地方,这点要注意了。
HP和SUN的JDK也有两种主要的回收策略,分别是对应高吞吐率的-XX:+UseParallelGC和快速响应时间的-XX:+UseConcMarkSweepGC。
本文主要是描述GC优化的纲领,指出不同的JDK优化对策的不同。详细的参数测试有待以后慢慢写。
Java 技术,IBM 风格: IBM Developer Kit 简介
Java 理论与实践: 垃圾收集简史 可以了解为什么不同的回收策略,表现出的gc时间会如此迥异。虽然Java 技术,IBM 风格: 垃圾收集策略,第 1 部分一文也叙述的很详细,但是个人觉得《垃圾回收简史》一文写的更明了,毕竟这是最原始的设计,省略了实现过程中添加的许多特性。
What is the Cause of the Performance Problem? 或者是How to Improve the Performance?
这是我们在系统开发、部署过程中都会面对的问题,但是却很难回答。从下面的这幅图就可以看到,一个系统的性能瓶颈(bottleneck),可能在网络、防火墙,也能在Http Server,Application Server,或者是数据库;系统中一个或者多个“短板”的存在,就能让系统无法达到设计时的目标,无法满足已经签在合同里的SLA……
虽然性能问题牵涉到方方面面,但是本系列关注点在于中间件这一层。希望能用合理的配置避免诸如OutOfMemory(某些情况下)、数据库连接不够的发生,同时能应用一些参数使系统在不优化代码的情况下有5%到100%的提升。
池(Pool)是WebSphere中最常涉及的概念之一。从网络、Web 服务器、Web 容器、EJB 容器,一直到数据源,每一个环节都线程池、连接池的影子。要想恰当配置这些池的大小,首先要了解漏斗模型。
通常,WebSphere应用中的一个请求到达服务器,到真正开始处理,要经过一系列的连接池。广域网上可能有大量的并发用户同时访问Web服务器,Web服务器上同时活动(Active)的连接可能高达10000个。但Web服务器到应用服务器(Web容器)的连接池大小可能只有200。Web容器到EJB容器的连接池更小,可能是80。然后,经过数据源(Data source)到数据库的连接最大可能只有25个。从Web服务器的连接池到数据库的连接池尺寸逐渐变小,像一个漏斗(funnel),所以称为漏斗模型。
IBM 000-253中有这么一道题:
According to the Upstream Queuing model for performance tuning, what reflets the correct application of recommended settings for maximum concurrent clients?
A Web Server=75, Web container=75, Datasource =25
B Web Server=75, Web container=50, Datasource =25
C Web Server=50, Web container=50, Datasource =50
D Web Server=25, Web container=50, Datasource =75
根据漏斗模型,那么很显然应该选B。
那么实际生产环境中就如此依样画葫芦就可以了么?后面的池一定比前面的小么?如果当前性能不行,增大池的大小就能提高么?
绝没有那么简单。后面的池小于前者,比如数据库连接池小于web线程池,默认的假定是:并非每个JSP和Servlet都需要访问数据库。如果你的应用是数据库密集型的应用,基本上每个JSP和Servlet都需要访问一次或多次数据库,而且系统中还有一些不经过jsp或Servlet的后台进程。那么数据源的连接池就必须大于web容器线程池,否则会报无法得到连接的错。
IBM HTTP Server的优化就是对Apache的优化。一般需要调整httpd.conf中如下参数:
MaxClients:用来定义Web服务器可以同时支持的最大并发连接数或并发用户数,默认值是600。这个值需要根据你所希望的同时支持的并发用户数来设置,一般是峰值的120%。当然这个值不能设的太大,毕竟Apache吃内存也是很厉害。我遇到的项目一般是不用调整的,大家可以根据实际负载动态的调整MaxClients。
将 IBM HTTP Server 配置为显示状态页面:
- 编辑 IBM HTTP Server 的 httpd.conf 文件,从此文件的下列各行中注释注释字符(#):
#LoadModule status_module, modules/ApacheModuleStatus.dll, #<Location/server-status> #SetHandler server-status #</Location>- 保存更改,然后重新启动 IBM HTTP Server。
- 在 Web 浏览器中,转至 http://yourhost/server-status。并且,单击重新装入以更新状态。
- (可选)如果浏览器支持刷新,那么转至 http://your_host/server-status?refresh=5 以便每 5 秒钟刷新一次。
上图给出了一些其它参数的推荐值。注意Windows平台和其它平台的不同(ThreadsPerChild相当于Maxclients)。关于MinSpareServers, MaxSpareServers, 和StartServers 等的设置,以及MPM使用prefork或worker模块时的不同,可以阅读Apache Performance Tuning。
如果你的应用访问量很大,那么也许你需要优化一下操作系统的tcp/ip相关参数。 http://publib.boulder.ibm.com/infocenter/wasinfo/v6r0/index.jsp?topic=/com.ibm.websphere.nd.doc/info/ae/ae/tprf_tuneopsys.html
并修改“负载均衡”选项和“重试时间间隔”Web 服务器插件属性设置以提高性能http://publib.boulder.ibm.com/infocenter/wasinfo/v6r0/index.jsp?topic=/com.ibm.websphere.nd.doc/info/ae/ae/tprf_tunewebserv.html
要点就是:“通常,对于每个服务器 CPU,5 至 10 个线程将会提供最佳吞吐量”(现在的一个cpu可以用核来代替)。比如你的Pc Server有2块CPU,每块CPU都是4核,那么你一个Application Server可以设置的最小值和最大值可以分别为40、80。但是一般考虑到能充分利用CPU和Memory,或者为不同的应用启用不同的application server,一台Pc Server上并不仅有这么一个appserver,而且还有别的进程在占用着CPU,所以默认的10到50(Linux 系统上 25 个)是一个比较合适的值,当然更准确的值需要通过性能测试来确定。
在进行性能测试的时候,如果吞吐率不是很满意,或者在TPV中看到线程池占用一直是最大值,不要立刻就调大线程池的设置——往往吞吐率会更一步下降。这时候要注意CPU占用率的情况、vmstat的r列值,特别是System状态占用率的情况,如果接近10%,甚至超过10%,那么可以肯定系统在进程切换上面消耗的资源太多了。下调线程池的大小反而会提升吞吐率,而且会由于吞吐率的提升降低页面平均响应时间。
这篇文章也许会使你对线程池大小对性能的影响有个感性的认识。
设置的地方大家应该都晓得,单击服务器 > 应用程序服务器 > server_name > 线程池。
连接池的最小值,应该和性能测试时TPV观察到的jdbc平均大小一样,最大值根据实际需要设置,每次增长可以设置成大于1,增长一次到位。总之尽量避免连接池频繁的增长和收缩,减少wait的情况发生。
可以使用 Tivoli Performance Viewer 查找池中最优连接数。如果并发等待者的数目大于 0,但是 CPU 负载未接近 100%,那么考虑增加连接池大小。如果使用百分比值一直低于正常工作负载,那么考虑减少池中的连接数。
Application Server 将在使用该数据源的每个应用程序服务器中创建连接池的单独实例。例如:
- 如果运行包含三个服务器的集群,这三个服务器都使用 myDataSource,并且 myDataSource 的“最大连接数”设置为 10,那么可生成多达 30 个连接(3 个服务器乘以 10 个连接)
这是需要考虑的,别数据库端的连接大小不够了。此外,inactive timeout和timeout的时间应该大于收集时间。
这篇文章参考了IBM的inforcenter和developworks,给出了优化WebSphere池大小的一些经验值,但是真正合适的大小还要参考实际的情况,总之调优是个循序渐进的过程。
调整完了各种池的大小,接下来你需要对内存参数做些优化,这篇是纲领性的。
针对不同的JDK,你可以参考:
JAVA性能优化—Sun Hotspot JDK JVM参数设置
最及时的声音