這個項目本身並不復雜springboot做的網關請求其他dubbo服務,本身沒有邏輯的功能,主要是接收請求鑒權,請求dubbo服務。
運行一段時間cpu就升高到30%, 10%,40%,忽高忽低。原本認為是請求負載問題,增加服務器后仍然出現該問題,於是決定排查一下cpu
升高原因。
Jstack是Jdk自帶的線程跟蹤工具,幾種線程狀態
1.NEW
線程剛剛被創建,也就是已經new過了,但是還沒有調用start()方法,jstack命令不會列出處於此狀態的線程信息。
RUNNABLE
RUNNABLE這個名字很具有欺騙性,很容易讓人誤以為處於這個狀態的線程正在運行;事實上,這個狀態只是表示,線程是可運行的。一個單核CPU在同一時刻,只能運行一個線程。
BLOCKED
線程處於阻塞狀態,正在等待一個監視器鎖(monitor lock)。通常情況下,是因為本線程與其他線程公用了一個鎖。其他在線程正在使用這個鎖進入某個synchronized同步方法塊或者方法,而本線程進入這個同步代碼塊也需要這個鎖,最終導致本線程處於阻塞狀態,
2.WAITING
等待狀態,等待某個condition或monitor發生,調用以下方法可能會導致一個線程處於等待狀態:
wait() 不指定超時時間;
join() 不指定超時時間;
park() ;
3.TIMED_WAITING
線程等待指定的時間,對於以下方法的調用,可能會導致線程處於這個狀態:
wait(long timeout) 指定超時時間;
join(long millis) 指定超時時間;
sleep(long millis) 指定超時時間;
parkNanos(long nanos) ;
parkUntil(long deadline);
4.TERMINATED:線程終止。
具體使用:
1.top命令找出最高占用的進程 PID
2.查看高負載進程下的高負載線程:top -Hp 【PID】 (或 ps -mp PID -o THREAD,tid,time)
3.找出最高占用的線程並記錄thread_id,把線程號 進行換算成16進制編號:printf "%X\n" thread_id,如結果4f50
4.查看高負載的線程找到具體執行方法:jstack 1555【進程】 | grep 4f50【線程】 -a 100 (-a 100 意思打印100行)
5.也可以導出進程的堆棧日志,找到4f50這個線程號:jstack 1555>/home/16143.log
我這里結果
"http-nio-60000-exec-17" #417 daemon prio=5 os_prio=0 tid=0x00007f23d000a000 nid=0x4f50 waiting on condition [0x00007f238601f000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000006c9168218> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078)
at java.util.concurrent.LinkedBlockingQueue.poll(LinkedBlockingQueue.java:467)
at org.apache.tomcat.util.threads.TaskQueue.poll(TaskQueue.java:89)
at org.apache.tomcat.util.threads.TaskQueue.poll(TaskQueue.java:33)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1066)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
發現是大量的lock問題,我們程序本身沒有用到lock,應該是springboot的問題。搜索之后發現該bug是springboot 2.2.*存在的問題。在github springboot issue下也找到了該問題,
降到2.1.13 正式環境運行,發現問題解決。
這里還有其他的分析工具,詳見帖子 https://www.cnblogs.com/caicz/p/14283376.html