记一次CPU飙升BUG

Posted soy-technology

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了记一次CPU飙升BUG相关的知识,希望对你有一定的参考价值。

https://mp.weixin.qq.com/s?__biz=Mzg3NjEzODQ4NQ==&mid=2247483690&idx=1&sn=7c926f40010fa6c927e34ae872a050ed&chksm=cf379bb0f84012a67c3fd36660695525b5254eb0720ff609f4bceb93d33fdf8c16847f60c9ae&mpshare=1&scene=23&srcid=0331altU001YYDNZzAMY4uXO#rd

 

 

 

 

一.前言

    上线后,CPU飙升到100%,怎么办?马上重启?大错特错,马上重启只会让这个雷石沉大海,治标不不治本,等待你的下次的历史重演!

二.现象

    监控告警,某机器的CPU飙升到100%

 

三.分析

     第一步,通过以下指令找到CPU高的进程号

     top -p `pgrep -d , java`

第二步,通过以下指令找到CPU高的线程号

top -Hp 进程号

第三步,通过以下指令把线程号转换成16进制

printf"%x\n" 线程号

第四步,通过以下指令打印线程的stacktrace

jstack 进程号 |grep 16进制线程号 -A 50

第五步,分析stacktrace的信息,定位哪个地方导致的CPU占用率高

第六步,从上面的截图可以可以定位到了FundClearRecordCtrl这个类里面的存在HashMap使用不当,导致死循环引发的CPU飙升

 

    1、正常情况下

技术图片

2、线程不安全,多线程并发的情况下,假如两个线程T1和T2,会造成e1.next = e2,而e2.next = e1,即形成环形,会导致死锁,然后现象就是CPU飙升

 

排查方向基本明朗,接下来让我们回到具体问题中,来解决问题!

 

四.解决

HashMap线程不安全,对于久经沙场的小伙伴们来说,这种认知还是有的,但是为啥还会入坑呢?

 

这个类没有明显的把HashMap作为公共变量,应该不存在多线程去操作HashMap的情况呀?

不能怪小伙伴,这个bug还真不好找,隐藏得有点深!

小伙伴也是无意中踩了坑,为什么说这个BUG隐藏得深呢?

 

由于DB资源紧缺,为了减少DB的直接操作,在DBUtil加了缓存,小伙伴在调用DBUtil的情况下,拿到的缓存的HashMap,此时该HashMap就是一个公共资源了,对于线程不安全的HashMap在多线程并发的情况下,理所当然的就进入了死循环!

 

总结

1、遇到CPU飙升,第一时间不好重启,先找到CPU高的类,确定好排查方向;

2、HashMap线程不安全,多线程并发场景下建议使用ConcurrentHashMap;

 

PS:上面的HashMap线程不安全讲得有点粗略,下次单独跟大家讲一下HashMap、HashTable和ConcurrentHashMap

 

以上是关于记一次CPU飙升BUG的主要内容,如果未能解决你的问题,请参考以下文章

记一次new ArrayList导致的cpu飙升问题排查

记一次Linux server偶发CPU飙升问题的跟进与解决

记一次MongoDB CPU飙升至99%问题的解决

记一次服务器被植入挖矿木马cpu飙升200%解决过程

开会时CPU 飙升100%同事们都手忙脚乱记一次应急处理过程

记一次 .NET 某旅行社Web站 CPU爆高分析