Linux部署web項目CPU爆表問題分析


  • tags:CPU
  • categories:problems
  • date: 2017-04-28 21:42:26

最近在開發微信公眾號時候,遇到了一個蛋疼的問題,就是發布這個項目到tomcat上時候,不一會,就會出現cpu爆表直接爆表到160多,汗....,然后上網查詢資料,多次結合項目本身情況進行實踐,最后終于是解決了這個部署項目CPU爆表問題,下面就想說說我的這個問題的出現,到如何應對,到最后解決問題的過程,希望自己能從這次經驗中汲取教訓。


微信截圖_20171119111701.png

問題出現

在開發微信公眾號時候,開發了兩個項目,一個是基于微信公眾號生態圈的一個用于分享文章賺取傭金的項目;還有另外一個則是為了前端安卓接口調用的項目。在開發完成,部署到阿里的linux服務器上tomcat時候,啟動tomcat服務,就會出現cpu爆表的情況。是如何發現了部署的java web項目致使linux服務器cpu爆表呢,是在聯調測試時候,發現剛開始調用服務可以使用,但是速度很慢(當然也跟我們買的阿里服務器硬件配置性能有關),之后再進行測試,發現,服務器不進行響應了。感覺就像掛掉了一樣。之后使用top命令后發現,TMD,java進程的cpu使用率已經爆表到160多了。。。。

top_cup.png

問題分析總結

這時候,當然要看我們的項目日志信息,再項目開發中,日志真的是很有利的工具。再開發時候可以通過log.info對不能進行本地測試的項目,在服務器上測試,另一方面,又可以通過log.error將系統報錯的日志信息打印出來,以供我們進行分析和處理。通過在日志中查看,發現了錯誤信息:

2017-04-28 19:04:43:078 ERROR http-bio-8081-exec-24 [90] pub.source.filter.XssInjectionFilter -
org.springframework.web.util.NestedServletException: Handler processing failed;
 nested exception is java.lang.OutOfMemoryError: PermGen space

發現,特么的是java的JVM內存溢出了。真的,寫java代碼都能內存溢出,臥槽,可以找塊豆腐自殺算了。。。不過想想,在公司的這個tomcat服務上可以部署有不少web項目啊,這個內存溢出還真的是非常有可能是這個造成java web項目cpu爆表致命的問題。

所以,當發現了是java的permGen(項目使用的是jdk1.7)永久區域部分對象太多了,導致溢出了。在jvm中與內存相關的,當然是GC啦。當然啦,這僅僅是初步的懷疑。接下來,打算使用jstack對這個爆表的進程進行線程分析,看看具體的問題到底出現在哪里。

  • 第一步,先使用top命令查看java爆表對應的進程:

    top_cup.png

  • 第二步,使用pidstat命令查看上述java進程中占用cpu高的線程信息
    當從第一步可以看到,進程號為17729的java進程的CPU使用率爆表到一百多了,這時候,我們可以使用pidstat命令來查看其內部的子線程的tid:

    tids.png

我們從上表就可以看出占據系統cpu的主要是tid=17731,17732,17733三個線程。這三個線程對CPU的使用率分別為62.38,63.37,36.63。找到線程號后,我們就可以繼續操作。。

  • 第三步,將上述得到的tid(線程號)轉換成十六進制:
    為下面jstack命令過濾線程nid號做處理,將tid轉換成十六進制處理: printf "%x\n" tid
# printf "%x\n" 17731
4543
  • 第四步,使用jstack命令,結合進程號,線程號查看具體線程信息:
    使用jstack對java web項目程序進行線程分析,使用命令:
jstack pid(進程號) |grep tid(子線程號) -A30(顯示行數)
jstack_result.png

可以看到上述的三個線程的nid=0x4543,0x4544,0x454c正好與第二步中主進程號為17729中占用cpu較高的三個子線程tid(十六進制)相對應匹配。所以,再結合log日志中的java.lang.OutOfMemoryError: PermGen space,就知道是由于JVM垃圾回收有關系,具體相看gc的信息,可以使用jstat -gc命令來查看,這里就省略了。主要就是永久區保存的對象太多,導致JVM內存模型中新生代,老年代的GC回收頻發,就占用了系統的CPU使用權,導致cpu爆表,并且程序的處理也異常了

  • 最后,則是要根據自己服務器的配置,對tomcat的內存GC進行必要的優化配置:
    需要對$CATALINA_HOME/BIN或者$CATALINA_BASE/BIN下面的catalina.sh進行編輯配置。vim $CATALINA_HOME/bin/catalina.sh,在第一個cygwin=false前面使用JAVA_OPTS進行配置。
JAVA_OPTS="-Xms512m -Xmx1024m -Xss1024K -XX:PermSize=256m -XX:MaxPermSize=512m"
# OS specific support.  $var _must_ be set to either true or false.
cygwin=false

其中,(JDK1.7)-Xmx表示JVM最大可用內存,-Xms表示JVM初始內存大小,-Xss則是設置每個線程的堆棧大小,-XX:PermSize則是設置持久代(永久區)初始大小,最后MaxPermSize當然是表示JVM最大永久區內存大小。(根據自己實際情況進行配置)


總結

在實際開發或者上線項目的時候,遇到問題,需要我們多思考,結合自己實際情況。在代碼規范編寫前提下,針對后臺的日志進行查閱問題和分析可能的情況。在有些思路的情況下,結合網上網友的答案或者案例,針對自己項目平臺問題進行逐一排除問題,更可以使用jdk一些自帶的JVM工具命令來操作分析,這樣更能鍛煉我們的獨立思考和使用jvm工具分析的能力。

在問題排查過程中,發現網絡上也有不少的這種部署web項目導致cpu爆表的問題,當然這些案例都是可以值得我們借鑒的,但是實際上還是需要我們自己手動進行實踐和排查。這個內存溢出當然僅僅是cpu爆表的一種可能性而已,具體還是要結合自己的場景進行分析實踐~~~

參考:
記錄 Linux環境下java web項目CPU爆表 “事故”,肇事者:GC
Java線上應用故障排查之一:高CPU占用
GC task thread#0 (ParallelGC) 占用cpu過高

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容