不断优化配置,逐步提高性能——我的一次性能测试经历

        近日,合作伙伴想要针对我们的应用服务器做一个性能测试,测试的基础是伙伴原有的一个功能庞大而结构复杂的业务系统,目的是看应用服务器是否能够满足业务系统的需要,并对应用服务器做一个总体评价。由于硬件资源有限,硬件服务器的配置为:2颗四核的志强E5520,8G内存,250G硬盘,一台普通PC Server,操作系统使用的是Windows Server 2003 SP2.

        在测试初期,客户端并发在100的时候,跑上不到1小时,服务器基本就没有反应了,此时查看应用服务器的JVM堆,都已经满满的了,而且非常平稳(几乎没有垃圾收集),貌似是客户端100并发的时候,内存都已经用尽了。但是内存一直得不到释放,想想看可能有这么几个原因:

  1. 应用系统内部存在内存泄漏,导致JVM不能及时执行垃圾回收,最终导致内存耗尽
  2. 应用系统在Session中放入太多的大对象数据,导致内存占用过高
  3. JVM参数设置不恰当,导致JVM不能及时垃圾回收(这条是在本次测试过程中总结出来的,这也是平时最容易碰到的问题,想想之前开发时碰到的一些问题,也许跟这个关系巨大)
  4. 应用服务器存在bug

分析一下,客户描述应用是一个省级的业务系统,生产环境下最大并发数能达到1000左右,运行时也没有问题,而且业务系统已稳定运行很长时间,看样子1、2两条可能性不高。同时,查看此时的服务器资源占用情况,发现CPU(2颗4核超线程的CPU)使用率极低,一直在3%-7%之间,而其中有一个核,利用率一直在90%以上,甚至经常达到100%,而其他核心非常闲,没有任何运算在执行。此时,也没有使用过任何Java监控及管理工具,一时陷入困惑中。无意间翻看之前的一些针对应用服务器的测试报告,发现几乎所有的测试,都对Java运行的参数做了大量改动,尤其是指定了很多关于Java虚拟机的运行控制参数,在大体了解几个参数的功能以及具体的服务器情况之后,决定不妨一试。于是在Java的启动参数中加上了一些关于JVM堆栈及垃圾收集的一些参数,经过几次调整,最终使用了参数:“-XX:NewSize=500m -XX:MaxNewSize=500m -XX:NewRatio=2 -XX:SurvivorRatio=8 -XX:+UseParallelGC -XX:ParallelGCThreads=8”(关于这些参数的意义,将在以后的文章中逐渐补充,或者可以搜一下),在此次参数改动之后,系统的8个核心,在闲(没有接收大并发)的时候一直处于10%左右的使用率的情况,估计这些核心在一直不停的进行垃圾收集,而此后,再也没有出现之前发生的内存一直被占用,系统没有反应的情况。甚至并发达到300时,系统运行效率仍然很高。至此,总结出一条结论:所有的Java系统都是运行在JVM之上,JVM的性能直接影响整个系统的性能,好的JVM是好Java应用系统的基础。当你的Java应用出现性能瓶颈的时候,首先考虑优化JVM启动参数。

另外,据说为保证系统在性能测试时的效率,防止JVM进行FullGC,可以将JVM的FullGC关闭,即在启动参数中加上“-XX:+DisableExplicitGC”。

在性能测试中出现的另外一个情况是:系统反应慢,但是应用服务器所在的服务器资源占用率很低,缓慢的反应速度使测试再次陷入僵局。此时,仍然是一个意外,解开了谜题。使用应用服务器内置的数据库连接池监控工具,发现数据库连接池中存在大量等待的线程,最多时甚至到了将近200个,难道是数据库连接池不够大?于是放大连接池的容量一倍,最大连接数达到300个。在重启数据源之后,系统性能立马提升,瓶颈消失了。

由此看来,影响Java应用的性能的最常见的2个问题就是:JVM的效率以及数据库连接池。配置一个最合适的JVM就成功了一半,再加上一个合适的数据库连接池(当然也可以使用Spring等管理连接池甚至自己编写相关的数据库连接管理工具),剩下的就只有开发一个优异的应用系统了。

另外,一个好的管理监控工具也可以成为提高性能的辅助手段。JDK5.0以上的jconsole工具,已经非常直观的将JVM内存及线程信息显示出来了,基本上可以满足一般系统的需要。IBM、Oracle的Java虚拟机也提供了很多性能监控管理工具。这里再加一句,如果应用系统在运行时出现性能问题,或者出现类似内存一直占满,CPU比较闲的情况,可以使用JConsole提供的手动GC按钮,强制执行一次GC,再查看内存情况,也许这时候问题就迎刃而解了。

最后,还是要阐述一下,没有最好只有最均衡,这是原来做开发的感悟,现在看来是整个软件领域的公理。由于此次针对压力测试,会进行一些性能优先的参数配置,而实际测试过程中,由于网络或其他原因,总是导致数据库连接失效,在重新启用闲置数据库时,未进行连接有效性检查,最终导致系统全部无法获取数据库连接,并进入一个永远使用无效数据库连接的“死循环”里面。此时,综合考虑稳定性与性能,最终决定放弃一部分性能,来保证稳定性,最终,应用服务器取得了一个较好的性能与稳定性,得到客户赞同。

你可能感兴趣的:(工作总结,Java)