一个Tomcat高CPU占用问题的定位

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一个Tomcat高CPU占用问题的定位相关的知识,希望对你有一定的参考价值。

案例背景:

前段时间项目发布了一个V2.1.2大的版本以后,IDC机器CPU不时会突然飙升,而且是“根本停不下来”的样子,一上去了就是100%。想来也纳闷

虽然发了版本,但没有太耗CPU的功能,不应该会让CPU一下子从20%左右飙升到100%,而且是间歇性的,想想也应该是项目本身固有的bug,只不过现在访问量大了才暴露出来。

 

1、通过top命令看看是哪个进程当用了大量的CPU,得到pid

 

2、top -H -p [pid]找出此进程中CPU占用排在前头的活动线程,把pid都记录下来。

 

3、通过jstack -l [pid] >  [pid].stack,得到线程堆栈,看看各个线程都在做什么事情。根据上面记录下来的高CPU占用线程的pid在pid.stack文件中找到对应的线程,发现这几个线程都是GC线程。

这个时候我觉得应该是有内存泄露,导致GC过于频繁,于是jmap查看内存堆栈信息,并作了一些优化,还对原先的日志处理方式作了优化。

发布,看起来有效果,可正常运行了几天了后,又有两台机的CPU给飙上去了,看起来根本问题没有得到解决。

 

4、又得重新来分析了! 先vmstat来看看机器的情况,发现当前的排队线程有时高达76,低时也有10个以上,已经超出了CPU数。

技术分享

既然是线程问题,还是jstack -l [pid] 来看线程堆栈,这次不再草草下结论,细细看每个线程都在干啥!发现有很多线程的执行都停留在saveUserAuthDetails方法中某一行:

技术分享

userAuthnBornTime是一个HashMap对象,更关键的是它是static的,也即所有对象公用,这个HashMap对象被用来保存登陆态的过期时间,很明显是读大于写,但是写也不少,在访问量大时,

大量的并发线程都需要操作这一个对象,导致很多读操作都处于忙等待状态。前面的在等待,后面还不停有请求进来,进一步加剧,因此在访问量突然增加时会直线飙升并且降不下来。

还是因此第一次太果断!

 

知道了原因,便得找解决方案了,了解Java的java.util.concurrent包自然会想到可以用ConcurrentHashMap来代替HashMap,以提高高并发情况下的性能,

ConcurrentHashMap不同于直接使用基于HashMap的同步操作的地方在于它内部同时保存了数据的多份拷贝,允许多个线程并发读,从而提高性能,

更多ConcurrentHashMap相关的介绍可找GOOGLE大神,相关文章太多了!

 

使用ConcurrentHashMap替换HashMap以后,果然机器CPU都能稳定在20%左右。

 

以上是关于一个Tomcat高CPU占用问题的定位的主要内容,如果未能解决你的问题,请参考以下文章

生产环境CPU过高问题定位

Java如何定位占用CPU比较高的问题

谈谈Tomcat占用cpu高的问题

使用Process Explorer和Clumsy定位软件高CPU占用问题

tomcat - CPU高占用问题记录

借助工具软件Clumsy和Process Explorer定位软件高CPU占用问题