事情是這樣的,最近小碼仔負責的項目預約今天凌晨2點上進行版本更新。前幾天測試小姐姐對網站進行壓力測試,觀察服務的CPU、內存、load、RT、QPS等各類指標。java
在壓測的過程當中,測試小姐姐發現咱們其中一個接口,在QPS上升到400之後,CPU利用率急劇升高。web
在這裏我再也不對CPU
、內存
、load
、RT
、QPS
等作過多贅述,畢竟這幾個點中的任何一個拿出來探討,一篇文章都不必定寫的完。有興趣深究的小可愛就本身動手查一下吧。服務器
這裏我僅對QPS
及CPU利用率
作簡單的概述。微信
❝QPS每秒查詢率,QPS是對一個特定的查詢服務器在規定時間內所處理流量多少的衡量標準。QPS越高說明,在特定時間內服務器所處理的流量越大。多線程
❞
❝CPU利用率是來描述CPU的使用狀況,它代表了一段時間內CPU被佔用的狀況。使用率越高,說明機器在這個時間上運行了不少程序,反之較少。編輯器
❞
瞭解了這兩個基本的點,接下來就來一塊兒看看我具體是怎麼定位的吧。工具
測試小姐姐反饋這個問題後,我登陸到服務器,作了如下操做:性能
登陸服務器,執行top命令,查看CPU佔用狀況:學習
$top
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
44529 root 20 0 4289m 874m 13312 S 123.0 10.9 10:39.73 java複製代碼
top
命令查看全部進程佔系統CPU的排序,它是Linux下經常使用的性能分析工具,可以實時顯示系統中各個進程的資源佔用情況,相似於Windows的任務管理器。測試
咱們來看一下這些指示符表明什麼:
PID — 進程id
USER — 進程全部者
PR — 進程優先級
NI — nice值。負值表示高優先級,正值表示低優先級
VIRT — 進程使用的虛擬內存總量,單位kb。VIRT=SWAP+RES
RES — 進程使用的、未被換出的物理內存大小,單位kb。RES=CODE+DATA
SHR — 共享內存大小,單位kb
S — 進程狀態。D=不可中斷的睡眠狀態 R=運行 S=睡眠 T=跟蹤/中止 Z=殭屍進程
%CPU — 上次更新到如今的CPU時間佔用百分比
%MEM — 進程使用的物理內存百分比
TIME+ — 進程使用的CPU時間總計,單位1/100秒
COMMAND — 進程名稱(命令名/命令行)
複製代碼
經過執行top
命令,我看到,進程ID爲44529的Java進程的CPU佔用率達到了123%,基本能夠定位到是咱們的Java應用致使整個服務器的CPU佔用率飆升。
固然,Java是單進程多線程的,那麼,接下來我就看了這個PID=44529的這個Java進程中的各個線程的CPU使用狀況,一樣是用top命令:
$top -Hp 44529
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
44580 root 20 0 4289m 874m 13312 S 16.2 10.9 3:02.96 java複製代碼
經過執行top -Hp 44529
命令,我發現,在44529這個進程中,ID爲44580的線程佔用CPU最高。
經過top命令,我定位到了致使CPU使用率較高的具體線程, 接下來就要看一下具體是哪一行代碼存在問題。
首先,我把44580這個線程轉成16進制:
$printf %x 44580
ae24
複製代碼
接下來,根據該16進制值去打印的堆棧日誌內查詢,查看該線程所駐留的方法位置。並經過jstack
命令,查看棧信息:
$jstack 44529 |grep -A 200 ae24
"System Clock" #28 daemon prio=5 os_prio=0 tid=0x00007efc19e8e800 nid=0xae24 waiting on condition [0x00007efbe0d91000]
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.concurrentC.TimeUnit.sleep(TimeUnit.java:386)
at com.*.order.Controller.OrderController.detail(OrderController.java:37) //業務代碼阻塞點
複製代碼
經過以上代碼,咱們能夠清楚的看到,OrderController.java的第37行是有可能存在問題的。
而後我找到項目中OrderController.java的第37行,仔細分析發現因爲本身的粗心,代碼存在邏輯上的漏洞。修改重構以後,問題解決。
以上就是本次問題排查的整個過程。主要用到的有:top
,printf
,jstack
等指令。
使用top
指令查看當前佔用CPU較高的進程PID;
查看當前進程消耗資源的線程PID: top -Hp PID
將線程PID轉爲16進制,根據該16進制值去打印的堆棧日誌內查詢,查看該線程所駐留的方法位置。
經過jstack
命令,查看棧信息,這步基本上已經可以定位大多數問題了。
項目今早凌晨兩點上線,昨晚通宵加班,早上回到家剛睡兩個小時,隔壁鄰居開始裝修,鑽牆、砸牆,劈里啪啦、咕咕咚咚,被吵得實在沒法入睡(感受已在猝死的邊緣試探)。因而起牀寫下這篇文章,也算是記錄2020年第一次加班吧。
最後,感謝各位的閱讀。文章的目的是記錄和分享,若文中出現明顯紕漏也歡迎指出,咱們一塊兒在探討中學習。不勝感激 !
若是你以爲本文對你有用,那就給點個贊吧,你的鼓勵和支持是我前進路上的動力~
歡迎關注個人微信公衆號【小碼仔】,咱們一塊兒探討代碼與人生。