問題背景
前不久技術學院負責人讓我幫助維護下?講堂、積分管理等?個系統,這些系統功能都已經很穩定,也不會再有新的功能開發,但是?講堂系統自上線后,每過?段時間就會出錯,導致學員?法報名課程,希望我幫助解決下,這種累積下來的問題解決起來?較難,但是對能?提升幫助很大,我欣然接受了,所以就有了這次“艱苦”的問題排查和解決之旅,
解決思路
本人未參加過大講堂和積分系統的開發,解決問題?先要最?化的了解系統背景、問題發?時的系統表現等資訊,技術學院的同事和我說,負責系統的開發?員已經換過?波了,現在基本已經找不到了解系統的開發?員了,但是也反饋了以下資訊:
1、系統是16年公司應屆?培訓時做的項?,
2、其他系統運?良好,就是?講堂系統偶爾會報錯,導致學員?法報名,重啟下就好了,果然是“重啟?法”好啊,
3、系統出錯的頻率不?,但是貌似很有規律,?半個?左右出現?次,
根據以上描述,特別是出錯后“重啟?法”特別有效,出錯頻率基本固定,通過這兩點基本上可以斷定是資源泄露導致的問題,既然確定是資源泄露問題,對于 Java 應?來說排查?向也就確定為以下2個?向:
1、物件泄露
2、執行緒泄露
3. 處理程序
前文提過本人并未參與專案開發,所以整個排查大部分是通過 linux 和 jvm 的?些命令列輔助功能來進行的,下面是整個排查程序:
1、 首先通過 jps 確定 Java 應用的行程 id
sudo -u tomcat jps -lv | grep qtscore
2、 排查記憶體泄露
通過持續觀察 GC 日志檔案 /home/q/www/qtscore/log/gc.log 檔案,發現 GC 執行頻率正常,特別是 Full GC 執行也并不頻繁,雖然記憶體使用量在持續增長,但是并不明顯,
為了確認業務代碼是否存在泄漏,通過 jmap 查看了堆內物件分布情況,切記此命令會導致行程暫停,如果是 qps 高或者回應時間要求高的應用慎用:
sudo -u tomcat jmap –F -histo 11035
存泄露的可能性,
3、 排查執行緒泄露
top -H -p 11035
通過結果可以看出執行緒已經高達4038,應用中dubbo執行緒池默認配置是200個執行緒,tomcat執行緒池配置也是200個執行緒,所以這個執行緒數明顯不合理,參照另外一個同等應用,其執行緒數未超過500,所以可以初步判斷系統存在執行緒泄露,下?步只能查看執行緒堆疊資訊了:
sudo -u tomcat jstack -l 11035 > /tmp/qtscore_stack.log
系統中存在100多個“New I/O boss"執行緒,這個應該是 netty 執行緒池的 boss 執行緒,到這里基本上可以確認是執行緒池泄露引起的問題了,但是究竟是哪段代碼引起的,執行緒堆疊中并無業務相關代碼,只是 netty 執行緒池的代碼,所以無法判斷出引起問題的代碼源頭,只能先看看系統日志中是否有價值的資訊了,發現系統日志中頻繁報以下錯誤:
找到對應的源代碼進行查看,發現這是?個 dubbo 服務介面,而 dubbo 底層用的就是 netty,種種跡象表明問題應該就出在這里,仔細分析代碼后,發現這個 dubbo 介面拋出的例外 QtalkQueryException,居然沒有通過 api 暴露給呼叫方,也就是說呼叫方是無法正確反序列化這個例外的,初步推測可能就是這個原因導致 dubbo 未能正確處理執行緒池,導致執行緒池泄露了,將 QtalkQueryException 改為拋出 IllegalStateException 例外,發布上線,滿懷期待地等著問題被完美解決,過了一個星期后,通過 top 命令查看行程的執行緒數,發現執行緒數又飆升到1千1百多了,看來問題還是沒有解決,只能再排查了,但是基本上可以確定是執行緒泄露問題,而且是 netty 引起的,可是執行緒堆疊中 netty 的 worker 執行緒堆疊中沒有任何業務相關的代碼,應該是代碼間接用到了 netty 執行緒池,但是一時沒有了頭緒,只有找同事咨詢一下了,和幾個同事討論后,大家都認為最有可能用到執行緒池的就是異步請求,特別是一些HTTP客戶端,根據這個思路對代碼進行排查后,發現系統中有如下代碼:
這個 com.ning.http.client.AsyncHttpClient 底層用到了 netty 執行緒池,這個用法存在明顯錯誤,AsyncHttpClient 實體應該重用,而不應該每次使用時都創建一個,修改代碼后重新發布上線,一周后再統計應用執行緒數,發現執行緒數穩定在350個左右,確認問題得到了解決,但是故事還沒有結束,個人覺得既然應用報錯,日志應該有所體現才對,難道是被其他例外淹沒了?所以重新排查了出錯日期的日志,果然發現了以下錯誤資訊:
通過系統命令 ulimit –a 發現系統最大用戶執行緒數是4096,所以問題是創建的執行緒超過了系統最大用戶執行緒數限制,
經驗總結
回顧這次問題排查經歷,其實這個問題排查起來并不難,最初的排查方向也是對的,但是整個程序還是花費了很長時間,回顧整個程序,總結出以下經驗和教訓:
-
大規模使用的基礎組件(例如:Dubbo)不容易有問題,即使有問題也會被及時修復,所以還是要多分析自己撰寫的代碼,
-
排查問題首先要仔細分析系統日志,報錯的地方?般也就是引起問題的源頭,遵循和重視這個原則,通常可以大大提高排查問題的效率,
看完三件事??
如果你覺得這篇內容對你還蠻有幫助,我想邀請你幫我三個小忙:
-
點贊,轉發,有你們的 『點贊和評論』,才是我創造的動力,
-
關注公眾號 『 java爛豬皮 』,不定期分享原創知識,
-
同時可以期待后續文章ing??
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/236382.html
標籤:其他
