作者: 張首富
時間:2021-07-08
wx: y18163201
背景描述
我們目前所有的 java 服務都是封裝在 docker 里面的,今天做壓力容量測試的時候發現有個服務占用cpu 300%
,想找到是這個 java 程序的那個線程造成的問題,把問題反饋給開發讓他們去修復。
下面所使用的容器鏡像都是通過:Docker容器內執行 jvm 分析工具命令 文章內的打包方式構建的;如果你發現你的 jvm 參數不能使用,那么建議你參考我的 dockerfile 進行構建
分析過程
通過監控發現 A 服務占用 cpu 過高;(prometheus+grafana+cadvisor構建的監控)
等到宿主機上使用 top 判斷是否真的是這個容器造成的 CPU 高
top
進入交互模式 按鍵盤 c 是按照 CPU 使用率進行排序
確定是此服務沒有跑了。那么開始分析是這個進程的那些線程出現的問題;因為我們服務都是封裝在容器里,namespaces 和屬主機上是隔離的,所以我們到容器里面去分析
docker exec -it A sh
apk add openjdk8 //安裝 jvm 分析工具
apk add htop // 安裝 htop 我們能更加清楚的看到是哪個線程占用 cpu 高,不需要借助其他命令;
進到 docker 容器內執行命令htop
進去到 htop 頁面按shift+p
按照 CPU 使用率排序。
找到 cpu 使用率前幾的線程號。記錄下來
使用dk自帶命令jstack獲取此時的線程快照並輸入到文件中: jstack -l > ./jstack_result.txt 命令(為Java進程的id號)來獲取線程快照結果並輸入到指定文件。
jstack -l 7 > 1.txt
使用 printf "%x\n" 命令(tid指線程的id號)將以上10進制的線程號轉換為16進制:
/home/work # printf "%x\n" 162
a2
/home/work # printf "%x\n" 163
a3
/home/work # printf "%x\n" 169
a9
/home/work # printf "%x\n" 164
a4
轉換后的結果分別為a2,a3,由於16進制以0x開頭,所以對應的16進制的線程號為0xa2和0xa3。
我們在剛才生成的線程快照中找 nid=0xa2,nid=0xa3 的線程
然后把這些提供給開發讓開發去查看代碼。
到此 docker 容器內分析 java cpu 使用率高的問題排查完成,
補充
在屬主機上可以使用 top -Hp PID 來找線程使用 cpu 占用高的。