對於互聯網公司,線上CPU飆升的問題很常見(例如某個活動開始,流量忽然飆升時),按照本文的步驟排查,基本1分鐘便可搞定!特此整理排查方法一篇,供你們參考討論提升。html
線上系統忽然運行緩慢,CPU飆升,甚至到100%,以及Full GC次數過多,接着就是各類報警:例如接口超時報警等。此時急需快速線上排查問題。java
無論什麼問題,既然是CPU飆升,確定是查一下耗CPU的線程,而後看看GC。算法
1.執行「top」命令:查看全部進程佔系統CPU的排序。極大可能排第一個的就是我們的java進程(COMMAND列)。PID那一列就是進程號。
框架
2.執行「top -Hp 進程號」命令:查看java進程下的全部線程佔CPU的狀況。eclipse
3.執行「printf "%x\n 10"命令 :後續查看線程堆棧信息展現的都是十六進制,爲了找到我們的線程堆棧信息,我們須要把線程號轉成16進制。例如,printf "%x\n 10-》打印:a,那麼在jstack中線程號就是0xa.工具
4.執行 「jstack 進程號 | grep 線程ID」 查找某進程下-》線程ID(jstack堆棧信息中的nid)=0xa的線程狀態。若是「"VM Thread" os_prio=0 tid=0x00007f871806e000 nid=0xa runnable」,第一個雙引號圈起來的就是線程名,若是是「VM Thread」這就是虛擬機GC回收線程了post
5.執行「jstat -gcutil 進程號 統計間隔毫秒 統計次數(缺省表明一致統計)」,查看某進程GC持續變化狀況,若是發現返回中FGC很大且一直增大-》確認Full GC! 也可使用「jmap -heap 進程ID」查看一下進程的堆內從是否是要溢出了,特別是老年代內從使用狀況通常是達到閾值(具體看垃圾回收器和啓動時配置的閾值)就會進程Full GC。
flex
6.執行「jmap -dump:format=b,file=filename 進程ID」,導出某進程下內存heap輸出到文件中。能夠經過eclipse的mat工具查看內存中有哪些對象比較多,飛機票:Eclipse Memory Analyzer(MAT),內存泄漏插件,安裝使用一條龍;url
執行步驟1-5:spa
肯定是Full GC,接下來找到具體緣由:
執行步驟1-4:在步驟4jstack,可直接定位到代碼行。例如某些複雜算法,甚至算法BUG,無限循環遞歸等等。
執行步驟1-4: 若是有死鎖,會直接提示。關鍵字:deadlock.步驟四,會打印出業務死鎖的位置。
形成死鎖的緣由:最典型的就是2個線程互相等待對方持有的鎖。
代碼某個位置有阻塞性的操做,致使該功能調用總體比較耗時,但出現是比較隨機的;平時消耗的CPU很少,並且佔用的內存也不高。
思路:
首先找到該接口,經過壓測工具不斷加大訪問力度,大量線程將阻塞於該阻塞點。
執行步驟1-4:
"http-nio-8080-exec-4" #31 daemon prio=5 os_prio=31 tid=0x00007fd08d0fa000 nid=0x6403 waiting on condition [0x00007000033db000] java.lang.Thread.State: TIMED_WAITING (sleeping)-》期限等待 at java.lang.Thread.sleep(Native Method) at java.lang.Thread.sleep(Thread.java:340) at java.util.concurrent.TimeUnit.sleep(TimeUnit.java:386) at com.*.user.controller.UserController.detail(UserController.java:18)-》業務代碼阻塞點
如上圖,找到業務代碼阻塞點,這裏業務代碼使用了TimeUnit.sleep()方法,使線程進入了TIMED_WAITING(期限等待)狀態。關於線程狀態,不理解的飛機票:Thread類源碼剖析
執行步驟1-4:jstack多查詢幾回,每次間隔30秒,對比一直停留在parking 致使的WAITING狀態的線程。例如CountDownLatch倒計時器,使得相關線程等待->AQS(AbstractQueuedSynchronizer AQS框架源碼剖析)->LockSupport.park()。
"Thread-0" #11 prio=5 os_prio=31 tid=0x00007f9de08c7000 nid=0x5603 waiting on condition [0x0000700001f89000] java.lang.Thread.State: WAITING (parking) ->無期限等待 at sun.misc.Unsafe.park(Native Method) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:304) at com.*.SyncTask.lambda$main$0(SyncTask.java:8)-》業務代碼阻塞點 at com.*.SyncTask$$Lambda$1/1791741888.run(Unknown Source) at java.lang.Thread.run(Thread.java:748)
按照3.1節的6個步驟走下來,基本都能找到問題所在。
====參考====
https://mp.weixin.qq.com/s/g8KJhOtiBHWb6wNFrCcLVg