天天看點

CPU和記憶體飙高,服務頻繁重新開機,看完這篇就會了

作者:碼豐屋

“冷靜思考,遇事不慌。有問題不可怕,解決它就好了。”

本文通過引用企業中實際發生的問題,記錄問題定位、過程排查以及方案解決的完整經過。

發現問題

某天,日常檢查服務運作情況時,發現服務日志不列印,服務狀态卻正常,為了不影響測試人員測試,遂聯系運維人員重新開機,之後就好了,奇怪。

過了幾天,再次發現服務日志不列印,檢視K8S Pod狀态,顯示重新開機了好多次了,服務也處于卡停的狀态,top一下,CPU和記憶體居高不下,之後就是再次重新開機,如此循環。。

此時的我意識到,這是個問題,不能再一味的重新開機了,得去找到根本原因解決它,不然到了線上還得了?(此時的我一點都不慌,這可比增删改查有意思多了~)

排查定位

既然CPU和記憶體都飙高,那就一個一個挨着排查吧,先查CPU。

  • CPU飙高排查

1、首先 top 檢視CPU占用情況,拿到程序PID

2、在CPU高的時候,輸出該程序的所有線程的堆棧資訊

jstack -l [pid] > jstack.txt           

3、分析jstack.txt檔案

發現存在大量的locked <0x360347c8> (com.mysql.jdbc.util.ReadAheadInputStream) 資訊,如下圖所示:

CPU和記憶體飙高,服務頻繁重新開機,看完這篇就會了

jstack

此時,原因好像已經顯而易見了,大多數線程都卡在了資料庫的讀取上,而這時,又一個 資料庫連接配接失敗 的異常提示将矛頭指向了資料庫。

CPU和記憶體飙高,服務頻繁重新開機,看完這篇就會了

SQL逾時告警

這時候,有同僚反應,管理端的相關頁面打不開了,一直轉圈圈,肯定是同一個問題,走吧,找DBA。

跟DBA說明了情況和連接配接的資料庫後,經查,資料庫(從庫)一切正常,各項名額正常,也沒有耗時長的查詢什麼的,奇怪。

繼續找原因。。

後來,在DBA一通kill processlist的程序後,服務突然好了,系統頁面也能正常通路了。

為了解決心中的疑惑,在我不斷的追問下,終于真相大白,原來資料庫用的是主備模式,服務配置的資料庫連接配接是SLB的連接配接,在阿裡雲指向的卻是從庫的位址,是以從一開始查詢從庫就查錯了資料庫,實際上是主庫存在長時間的查詢,導緻部分表被鎖,在被kill之後就恢複正常了。

唉,一聲歎息,道盡那幾個小時的無奈~

  • 記憶體飙高排查

CPU高的問題解決了,但是服務每次重新開機後,記憶體就噌噌噌的往上竄,直到記憶體占滿重新開機,接下來該排查記憶體高的問題了:

1、top檢視記憶體占用高的程序,拿到程序PID:top

2、檢視該程序下CPU、記憶體都比較高的線程,拿到線程PID:

top -Hp [PID]           

3、将線程PID轉換成十六進制

printf "%x\n" [線程PID]           

4、分析jstack.txt 檔案

在上邊排查CPU時導出的 jstack.txt 檔案中查找步驟3得到的線程id轉換為十六進制後的值,發現這些線程都是GC線程,說明JVM在頻繁的GC

CPU和記憶體飙高,服務頻繁重新開機,看完這篇就會了

jstack

5、輸出堆記憶體資訊

jmap -dump:format=b,file=dump.phrof [pid]           

6、使用MAT分析dump檔案

發現80%多的記憶體都被jdbc的結果集占用了,說明此時正在從資料庫拉取大量的資料到記憶體。

CPU和記憶體飙高,服務頻繁重新開機,看完這篇就會了

dump

此時,根據上圖的分析顯示,已經可以确定:代碼中從資料庫查詢了大量的資料,一次性存放到記憶體,導緻記憶體快速被占用,達到服務設定的最大記憶體後,就會被重新開機。

解決優化

到了現在,CPU和記憶體飙高的根本原因已經查明,但是這個事情已經結束了嗎,并沒有。最終問題的矛頭指向了業務代碼,根據MAT顯示的結果集資料,定位代碼,因為資料量很大,是以就需要花費更多的精力去優化,在實作功能的基礎上,還要讓系統服務平穩的運作下去。

真的是,痛并快樂着。。

如有幫助,煩請點贊、關注。有任何問題請私信、評論。