压力测试tps性能下降问题解决方案
背景
测力测试时反映tps一直下滑的问题,为了重现该问题,开发一个简单交易进行测试,测试代码如下
录制该交易脚本,并放在LoadRunner11中进行测试,场景为10个用户同时启动并持续的跑。可以看到1分钟之后tps开始下降,并在后期持续下降。
此时分析服务端日志、javacore、heapdump、gc等,并未发现异常现象。修改服务端线程池相关等,但测试结果却是一如既往的下滑。记录服务端处理请求时间,发现一直很稳定,初步怀疑是客户端压力不够导致,但一直无具体证据,因此压测tps下滑问题一度搁置。
转折点
本周一时,一同事开始做压力测试,交流这个问题后,那边现场也开始了类似测试,但测试结果如出一辙。后来广发使用了LoadRunner中的按进程运行vuser,测试效果如下。可以看到,整个过程跑了3个小时,tps一直稳定在950左右,这下总算有了突破口。
分析
LoadRunner中按进程运行vuser与按线程运行vuser跑出来的结果竟然会有那么大区别,那么他们两者的结果为什么差别那么大呢。
LoadRunner中对这两种分别是这样说明的:
Ø 按线程运行vuser
启动多线程以便每台负载生成器计算机运行更多的vuser。
Ø 按进程运行vuser
禁用多线程并将每个vuser作为完整的进程运行。用于非线程安全协议
网上对于两者有这样的解释:
线程的资源是从进程资源中分配出来的,因此同一个进程中的多个线程会有共享的内存空间
那么回过头来使用神器javavisualvm查看下使用按线程运行vuser时mdrv.exe(lr跑vuser的程序)进程的内存使用情况,可以看到运行7分钟时间内fullgc执行了94次,仔细看下可以发现新生代为896k+64k*2=1024k,最大4992k,年老代为4m,最大59.125m。此时猜想为jvm内存分配太小导致的
调优
现在调整下虚拟机内存并使用同样的场景进行测试,jvm参数与测试结果如下:
Jvm参数:-Xmn128m -Xmx384m -Xms384m-XX:PermSize=64m -XX:MaxPermSize=128m
果然和猜想的一样,测试期间稳定运行,下面为本次的内存使用截图
可以看到年老代内存使用一直稳定在1.457m,持久代内存一直稳定在5.616m,
整个过程没有进行fullgc,垃圾回收全部在年轻代。
基于本次测试,继续调整基于本场景下的虚拟机参数,增大年轻代,缩小年老代与持久代。并使用同样的场景进行测试,jvm参数与测试结果如下:
Jvm参数:-Xmn320m -Xmx384m -Xms384m -XX:PermSize=12m -XX:MaxPermSize=12m
继续看测试过程中内存使用情况。
可以看到运行1:40期间,年轻代执行gc 2304次,耗时45.703s,相对于上次测试的运行1:10,年轻代执行gc 3228次,耗时35.965s,有一定的提升。
结论
此次发现的压力测试tps持续下降问题并非由服务端和客户端处理性能导致,而是由压测客户端内存分配不合理导致。
后续测试时如出现类似情况可选取按进程运行vuser,也可根据实际运行交易场景进行内存参数调整,保证后续测试正常进行。
附
按进程运行vuser时其中一个进程的内存使用截图: