-
旨在分享工作中遇到的各種問題及解決思路與方案,與大家一起學習. -- 學無止境, 加油 ! Just do it !
-
問題描述
-
執行環境描述
-
tomcat-8.5
-
單節點(該應用叢集20個節點) avg-tps 250,max-tps 350
-
tomcat max-threads:200 (下圖藍色線)
-
tomcat busy-threads 正常(下圖綠色線)
-
tomcat cur-threads飛昇(下圖黃色線)
-
每次黃色線上升時可以發現原本平均響應時間100ms內的介面響應時間均在3-10s
-
-
提出問題
使用grafana監控發現服務某個節點的cur執行緒數會暴漲直至Max-threads數且一直無法回收
-
期望
解決cur-threads回收問題,讓執行緒正常回收
-
-
原因分析
-
執行緒問題首先來一波jstack 上圖是當時某個節點執行緒飆升時dump下來的執行緒日誌,在這個時間點的執行緒中有大量的TIMED_WAITING 狀態,可以先複習一波執行緒狀態了,走起.
-
Java執行緒的5種狀態
-
新建狀態(New): 執行緒物件被建立後,就進入了新建狀態。例如,Thread thread = new Thread()。
-
就緒狀態(Runnable): 也被稱為“可執行狀態”。執行緒物件被建立後,其它執行緒呼叫了該物件的start()方法,從而來啟動該執行緒。例如,thread.start()。處於就緒狀態的執行緒,隨時可能被CPU排程執行。
-
執行狀態(Running): 執行緒獲取CPU許可權進行執行。需要注意的是,執行緒只能從就緒狀態進入到執行狀態。
-
阻塞狀態(Blocked): 阻塞狀態是執行緒因為某種原因放棄CPU使用權,暫時停止執行。直到執行緒進入就緒狀態,才有機會轉到執行狀態。阻塞的情況分三種:
-
等待阻塞 -- 通過呼叫執行緒的wait()方法,讓執行緒等待某工作的完成。
-
同步阻塞 -- 執行緒在獲取synchronized同步鎖失敗(因為鎖被其它執行緒所佔用),它會進入同步阻塞狀態。
-
其他阻塞 -- 通過呼叫執行緒的sleep()或join()或發出了I/O請求時,執行緒會進入到阻塞狀態。當sleep()狀態超時、join()等待執行緒終止或者超時、或者I/O處理完畢時,執行緒重新轉入就緒狀態。
-
-
死亡狀態(Dead): 執行緒執行完了或者因異常退出了run()方法,該執行緒結束生命週期。
-
-
Jstack中常見的執行緒狀態
-
RUNNABLE 執行緒執行中或I/O等待
-
BLOCKED 執行緒在等待monitor鎖(synchronized關鍵字)
-
TIMED_WAITING 執行緒在等待喚醒,但設定了時限(lock.wait(10))
-
WAITING 執行緒在無限等待喚醒(lock.wait(10))
-
複習完了,結合上面的執行緒日誌以及服務中高併發的介面,找到有用到lock鎖的介面,分析程式碼,到這一步基本算是找到解題思路了,如此多的執行緒等待是因為併發的查詢介面快取穿透了 接下來還要dump下這個節點的堆記憶體來具體分析,準確定位,下圖是堆記憶體日誌: 很明顯可以看到堆中的大物件內容,結合實際業務可以準確定位需要優化的介面了,那麼cur-threads執行緒數為什麼一直增長呢?為什麼不回收呢?帶著這兩個疑問,我們先去找下tomcat官網針對這兩個引數的描述;
-
-
上圖可以看到最大執行緒數預設是200,初始化空閒執行緒數10,與我們線上環境一致(附上圖中
-
上圖也是找的tomcat官網(附上圖中
-
總結
-
cur-threads一直增長的原因
-
介面併發且發生了大量快取穿透(執行緒日誌中大量time_wait執行緒是專案中防快取穿透使用的鎖),造成鎖等待,進而造成tomcat當前執行緒不夠用,所以cur執行緒資料增加,每次線上程數增加的時候介面響應均達到秒級別,可能建立Thread比較消耗資源,這塊有待驗證!
-
-
tomcat執行緒一直不回收的原因
-
Tomcat執行緒池每次從佇列頭部取執行緒去處理請求,請求完結束後再放到佇列尾部,在高併發下,每個執行緒都會在短時間內被使用,達不到1分鐘空閒被回收的條件
-
-
-
解決方案與建議
-
需要優化響應慢的介面(治本)
-
如果可以,降低介面併發(治標)
-
適當增加tomcat的maxThreads值可以提升應用效能(不是越大越好,最優配置數值需要模擬pro環境經過大量壓測對比得出)
-
-
優化後
-
本次改造有兩個點
-
降低併發(比如serv A->serv-B,查詢併發比較高,可以根據實際業務考慮在A系統做快取,降低B系統併發)
-
優化響應慢的介面 (如果業務複雜可以先考慮設計是否合理再考慮技術改造(多執行緒,快取中介軟體))
-
-
歡迎關注個人訂閱號:Java技術寶典 ,及時獲取最新分享.