一次性能调优

性能tuning和性能troubleshooting是有区别的。这次应该算是后者。因为系统很慢,每秒只能处理20多笔请求,用sar查看CPU利用率,只有2%。再用sar看了看磁盘,也不忙。相关数据库系统,第三方模拟系统都正常。压力机用的是Jmeter,是HTTP报文应该没有啥问题。那问题焦点就锁定在程序上。
  首先在程序的主路径上都打上日志,确定每个模块的执行时间点在哪儿。很快就发现请求在入队列缓存后,再出队列,居然要4秒时间。用JDK自带的Concurrent 队列,实际用不了一毫秒就能完成,为什么在我们程序里需要4秒?
  一开始怀疑入队列入的慢。查看代码,一切正常,入队列逻辑很简单,不可能很慢,后来发了单条请求试试,结果很快,1毫秒就完成进缓存,出缓存的操作。
  后来又怀疑JDK在UNIX上机器上补丁没有打全,通过google也排除了这个想法。
  早上时间很快过去了。我就反着想,要是我是个破坏者,怎么才能写出的代码把原来只需要1毫秒的事情变成4秒呢。这一下思路突然开窍了,从缓存读取的线程如果优先级很低的话,那被唤醒执行的机会就比较少,那缓存的消息就自然要花较长时间才有机会读出。于是更改了一下线程优先级到最高级别,效果立刻体现出来,这断代码由原来的4秒提高到几毫秒。
  代码还有一处显示更新数据库操作需要花的时间也是不可思议的长,大概也须有4秒。其功能非常简单的,就是更新数据库的状态表示业务完成。最初troubleshooting是排除了数据库瓶颈,后来又排除了数据库连接池的瓶颈(因为这个数据库连接池以前在性能测试测试过,没有问题),最后焦点还是在代码里,业务逻辑比较复杂,但都没有让速度变得如此之慢的代码。快到下班的时候,一个同事眼尖,发现方法声明用了synchronized,也就是同步了!!。从业务逻辑上看,此代码是线程安全的。当初用上,是啥原因不得知晓。但对于方法体具有主业务逻辑,且有IO(数据库)操作,用上synchronized,是极其风险的。后来去掉此关键字,性能马上由4秒提高了几十毫秒。

  修改了这俩处主要的地方,让测试人员在压力测试一下,程序TPS已经有100多了。且延迟只有200毫秒,提高了不少。再查看CPU,用到了10%,还不太满意。当然希望CPU能用的更多点,但考虑到程序序串行化处理的地方太多,导致CPU很难用上。或者也有可能是tomcat本生的效率导致CPU用不上。记得在以前的一次性能调优中,同样的web程序,用weblogic的吞吐量是tomcat的5倍多。
  当然CPU用不满一直困惑着我,碰到或者听说过别的项目都出现了这个问题,系统吞吐量小,延迟长,但硬件又没有问题,尤其是CPU,有得甚至不到20%。理论上讲应该是串行化操作太多导致CPU有劲无处使。可惜我也不知道怎么通过操作系统,或者虚拟机调优工具查看

  最后要结束调优的时候,测试人员反映连续压上几天,性能越来越慢,到最后几乎不再处理请求。这个现象以前遇到过,有种可能就是内纯溢出导致垃圾回收频繁。于是调正虚拟机最大内存为64M,让后在压力测试一下,通过jvisualvm,查看内存使用情况,果然到了后期,内存频繁变化,用jstat看,几乎一秒fullgc一次,难怪系统运行时间长了不再处理业务。
  下班时间到了,遇到内存泄漏的问题,感觉一时无法解决,就打算第二天再说了。

  后来这个问题通过看了整天代码和观察虚拟机,也没有发现。最后也是在熟习了此系统特点后才明白,原来并不是所谓的内存泄漏,而是该系统的缓存功能的溢出判断不正确,导致缓存里消息越来越多,最终缓存用满了内存空间导致的。


   通过以上调优,总结一下
   1 觉得对性能调优工具熟习是必须的,
   2 如果熟习系统功能,了解代码也是必须的,当然,如果是自己写的代码,有时候往往思维固定,很难看出来,还得找人帮忙看。
   3 需要把系统执行的各个部分时间打出来,任何好的系统,譬如UNXI,数据库等,总会包含这些数据的用于调优
   4 好的测试系统,一旦有新的调优观点,可以马上辅助实施。
   5 反向思维,如果系统有问题,可以把自己当着系统破坏者,看看如何才能让系统出问题
   6 最后就是觉得性能调优也好,troubleshooting也好,真急不来的

你可能感兴趣的:(jdk,多线程,tomcat,虚拟机,weblogic)