伺服器常見問題排查(一)——cpu佔用高、上下文頻繁切換、頻繁GC

2023-10-26 18:01:36

一般而言cpu異常往往還是比較好定位的。原因包括業務邏輯問題(死迴圈)、頻繁gc以及上下文切換過多。而最常見的往往是業務邏輯(或者框架邏輯)導致的,可以使用jstack來分析對應的堆疊情況。

使用jstack排查佔用率問題

當使用jstack排查佔用率問題時,可以按照以下步驟進行:

  1. 首先,使用top命令找到佔用率較高的程序,並記錄其PID。
  2. 接著,使用以下命令來檢視該程序中佔用CPU較高的執行緒:
top -H -p <pid>

該命令將顯示程序中各個執行緒的CPU使用率,以及執行緒的ID(TID)。
3. 根據執行緒ID(TID)獲取nid,可以使用以下命令:

printf '%x\n' <tid>

這將把TID轉換為16進位制格式的nid。
4. 然後,通過以下命令來檢視該執行緒的堆疊資訊:

jstack <pid> | grep 'nid' -C5 --color

該命令將顯示包含nid的堆疊資訊。注意,這裡使用了grep命令來過濾輸出結果,只顯示包含nid的部分。-C5表示在匹配項前後各顯示5行上下文資訊,--color則用於在輸出中新增顏色標記。
5. 除了逐個檢視執行緒的堆疊資訊外,還可以對整個jstack檔案進行分析。可以使用以下命令來統計各個狀態的執行緒數量:

cat jstack.log | grep "java.lang.Thread.State" | sort -nr | uniq -c

該命令將輸出各個執行緒狀態的數量,例如RUNNABLE、BLOCKED、WAITING、TIMED_WAITING等。如果WAITING或TIMED_WAITING的數量較多,那麼可能存在一些問題。

通過以上步驟,我們可以使用jstack來定位佔用率較高的問題,並進一步分析問題原因。

頻繁GC問題

通過使用jstat工具的-gc選項,我們可以觀察GC的分代變化情況,以便確定GC是否過於頻繁。具體來說,我們可以使用以下命令來觀察程序的GC情況:

jstat -gc <pid> 1000

在上述命令中,<pid>是目標Java程序的PID,而1000表示取樣間隔(以毫秒為單位)。通過這個命令,我們可以獲取關於Survivor區、Eden區、老年代(Old Generation)、後設資料區(Metaspace)的容量和使用量資訊,以及關於Young GC和Full GC的耗時和次數以及總耗時資訊。

具體來說,以下是一些關鍵指標的含義:

  • S0C/S1C和S0U/S1U:這兩個指標分別表示Survivor 0區和Survivor 1區的容量和已使用的容量。如果這些值接近或達到其最大值,則可能需要進行GC。
  • EC/EU:這兩個指標分別表示Eden區的當前容量和已使用的容量。如果這些值接近或達到其最大值,則可能需要進行GC。
  • OC/OU:這兩個指標分別表示老年代的當前容量和已使用的容量。如果這些值接近或達到其最大值,則可能需要進行GC。
  • MC/MU:這兩個指標分別表示後設資料區的當前容量和已使用的容量。如果這些值接近或達到其最大值,則可能需要進行GC。
  • YGC/YGT:這兩個指標分別表示Young GC的次數和所花費的總時間。如果這些值較高,則可能表明應用程式存在過多的短期物件參照,需要優化。
  • FGC/FGCT:這兩個指標分別表示Full GC的次數和所花費的總時間。如果這些值較高,則可能表明應用程式存在過多的長期物件參照,需要優化。
  • GCT:這個指標表示應用程式進行GC的總時間。如果這個值較高,則可能表明應用程式需要進行優化以減少GC的開銷。

通過觀察這些指標,我們可以更好地瞭解Java程序的記憶體使用情況和垃圾回收情況。如果發現GC過於頻繁或存在其他問題,我們可以進一步分析並採取相應的優化措施。

頻繁上下文切換

上下文切換會消耗CPU的時間,並導致程序真正執行的時間縮短,從而成為系統效能下降的一個因素。過多的上下文切換可能會使得CPU花費過多的時間用於儲存和恢復暫存器、核心棧以及虛擬記憶體等資料,從而影響系統的響應速度和吞吐量。

vmstat是一個非常有用的系統效能分析工具,它可以提供關於系統記憶體、CPU活動、分頁和上下文切換等資訊。

在使用vmstat檢視上下文切換情況時,可以顯示以下統計資訊:

  1. "cs"(上下文切換):顯示系統每秒上下文切換的次數。自願上下文切換(voluntary context switches)和非自願上下文切換(non voluntary context switches)都會被計算在內。
  2. "in"(中斷):顯示系統每秒中斷的次數。這些中斷可能來自硬體裝置、網路或其他原因。
  3. "r"(執行或可執行):顯示正在執行或等待CPU的程序數。這個統計資訊可以提供關於系統負載的總體檢視。
  4. "b"(阻塞):顯示處於不可中斷睡眠狀態的程序數。這些程序通常是在等待某些資源(如I/O操作)可用。

需要注意的是,vmstat命令的具體選項和輸出可能會因作業系統和版本而有所不同。在使用vmstat時,建議查閱相關檔案或使用"man vmstat"命令來獲取特定系統上vmstat的詳細使用說明和輸出解釋。

vmstat是給出整個系統總體的上下文切換情況,要想檢視每個程序的詳細情況就需要使用pidstat,加上-w選項就可以檢視程序上下文切換的情況 pidstat -w pid命令,cswch和nvcswch表示自願及非自願切換。

cswch(voluntary context switches):表示每秒自願上下文切換的次數
nvcswch(non voluntary context switches):表示每秒非自願上下文切換的次數
  1. 自願上下文切換:程序無法獲取所需的資源,導致的上下文切換,例如IO、記憶體等資源不足時,就會發生自願上下文切換
  2. 非自願上下文切換:程序由於時間片已到等時間,被系統強制排程,進而發生的上下文切換,例如大量的程序都在爭搶CPU時,就容易發生非自願上下文切換

系統上下文切換的次數為多少時是不正常的呢?

系統上下文切換的次數是否正常,取決於系統本身的CPU效能。一般來說,如果系統的上下文切換次數比較穩定,在數百到一萬以內,都應該算是正常的。然而,當上下文切換次數超過一萬次,或者切換次數出現數量級的增長時,就可能已經出現了效能問題。

具體遇到問題的時候,需要根據變化的上下文切換型別,再做具體分析。例如:自願上下文切換變多了,說明程序都在等待資源,有可能發生了I/O等其他問題;非自願上下文切換變多了,說明程序都在被強制排程,也就是都在爭搶CPU,說明CPU的確成了瓶頸;中斷次數變多了,說明CPU被中斷處理程式佔用,還需要通過檢視/proc/interrupts檔案來分析具體的中斷型別。