背景介紹
對於線上系統突然產生的運行緩慢問題,如果該問題導致線上系統不可用,那麼首先需要做的就是,導出 jstack 和內存信息,然後重啓系統,儘快保證系統的可用性。
這種情況可能的原因主要有兩種:
- 代碼中某個位置讀取數據量較大,導致系統內存耗盡,從而導致 Full GC 次數過多,系統緩慢。
- 代碼中有比較耗 CPU 的操作,導致 CPU 過高,系統運行緩慢。
相對來說,這是出現頻率最高的兩種線上問題,而且它們會直接導致系統不可用。
另外有幾種情況也會導致某個功能運行緩慢,但是不至於導致系統不可用:
- 代碼某個位置有阻塞性的操作,導致該功能調用整體比較耗時,但出現是比較隨機的。
- 某個線程由於某種原因而進入 WAITING 狀態,此時該功能整體不可用,但是無法復現。
- 由於鎖使用不當,導致多個線程進入死鎖狀態,從而導致系統整體比較緩慢。
具體情況及定位步驟
簡要的說,我們進行線上日誌分析時,主要可以分爲如下情況:
1、 CPU 比較高
-
通過 top 命令查看 CPU 情況,如果 CPU 比較高,則通過 top -Hp 命令查看當前進程的各個線程運行情況。
-
找出 CPU 過高的線程之後,將其線程 id 轉換爲十六進制的表現形式,然後在 jstack 日誌中查看該線程主要在進行的工作(jstack pid(進程pid) | grep 線程pid)。
這裏又分爲兩種情況:
- 如果是正常的用戶線程,則通過該線程的堆棧信息查看其具體是在哪處用戶代碼處運行比較消耗 CPU。
- 如果該線程是 VM Thread,則通過 jstat -gcutil 命令監控當前系統的 GC 狀況。
然後通過 jmap dump:format=b,file= 導出系統當前的內存數據。導出之後將內存情況放到 Eclipse 的 Mat 工具中進行分析即可得出內存中主要是什麼對象比較消耗內存,進而可以處理相關代碼。
2、 CPU 並不高
- 如果通過 top 命令看到 CPU 並不高,並且系統內存佔用率也比較低。此時就可以考慮是否是由於另外三種情況導致的問題。
具體的可以根據具體情況分析:
- 如果是接口調用比較耗時,並且是不定時出現,則可以通過壓測的方式加大阻塞點出現的頻率,從而通過 jstack 查看堆棧信息,找到阻塞點。
- 如果是某個功能突然出現停滯的狀況,這種情況也無法復現,此時可以通過多次導出 jstack 日誌的方式對比哪些用戶線程是一直都處於等待狀態,這些線程就是可能存在問題的線程。
- 如果通過 jstack 可以查看到死鎖狀態,則可以檢查產生死鎖的兩個線程的具體阻塞點,從而處理相應的問題。
本文主要總結了五種常見的導致線上功能緩慢的問題,以及排查思路。當然,線上的問題出現的形式是多種多樣的,也不一定侷限於這幾種情況。
參考
https://blog.csdn.net/keketrtr/article/details/54289134
https://blog.csdn.net/jerry024/article/details/8507589