一个性能测试项目,一个值得深思的问题。
1.症状:
12小时稳定性压测,压力恒定
系统响应时间随压测时间的增长而不断增大
如图所示:
2.性能分析,性能问题定位
1) 系统负载检查:在压测过程中,压力恒定,CPU 利用率没有较大的波幅
2) 磁盘IO检查:在压测过程中,磁盘读写稳定,没有较大的请求等待队列
3) 网络检查:在压测过程中,无较大的数据传输,网络延迟正常,测试环境的网络正常。
4) 内存检查:系统可用内存逐渐减小,JVM内存逐渐增大,不排除随着压测时间的增大而JVM崩溃的极端情况发生。
通过分析jvm dump发现,在测试结束时,jvm内存在较多的与JDBC通信的等待线程。此类线程占用了较多的JVM内存空间
根据上面的第4点,初步判断是与db的交互出现了性能问题。
转到DB查看性能监控日志,对比测试开始和测试结束时的性能日志,发现其中一条SQL的查询性能差别极大。在初始时查询响应时间在10ms以下,但在测试结束时,达到800多毫秒,增幅达到80多倍,占据了整个transction响应时间的95%。
获取该SQL的DB执行计划:
可见该SQL在查询过程中使用了表扫描的操作,该操作的cost为2898,占据了99%的执行时间。
再查询该表的大小, 发现该表在测试开始时仅有一千条左右的记录,但在测试结束时,已经增加到了30万条左右的记录,由此,真相大白,在测试刚开始时,表数据记录较少,即使使 用表扫描查询,DB响应也较快,但随着测试的进行,表中的记录迅速增长,此时,表扫描的性能迅速下降,成为性能瓶颈.
3.性能调优
知道了问题所在,解决起来就容易了
SQL使用表扫描进行查询,是缺少了对应的索引,为此,我们给它建立了恰当的索引,在建立索引后,再查看该SQL的执行计划:
如图所示,先前的Table access full 已经变为table access by index rowed ,消耗的资源由2898降低到4,完全解决了性能瓶颈。此时,再进行12小时的稳定性压测,系统性能稳定,不再出现响应时间不断增长的现象。
通过该案例,可以得到一条有用性能经验,在记录增长较快的表中,即使初始查询的响应很快,也要为查询SQL建立合适的index,避免DB因为使用不恰当的执行计划而导致不必要的性能开销,从而避免系统产生数据查询上的性能瓶颈。