<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 167,  comments - 30,  trackbacks - 0

    問題現象

    vrs后臺系統從某一時間點,根據已查結果,追溯到幾個月前上線的PGC審核功能引起。

    近期大概一周左右運營使用時會反饋系統訪問越來越來慢,最終系統崩潰,無法訪問。因為之前媒資每周都會有功能上線,把這個問題覆蓋掉了,未能很快暴露出來。
    實際上,通過Zabbix觀察監控cpu、swap占用都是比較高的。
     

    1031問題分析之CPU 100%

    10-31日出現過一次問題,服務器上執行top命令按鍵1觀察始終有一個cpu占用總100%,懷疑可能是因后臺服務請求過多CPU繁忙導致訪問慢。

    將后臺服務切到備機,通過堆棧分析具體那段代碼引起的CPU占用100%問題。

    問題定位過程:

    1)jps -m 非常方便直接定位所有的Java進程pid

          [root@cdn ldw]# jps -m | grep 28081

          6687 WatchdogManager start -conf /ldw/conf/resin/resin-mms-webapp-28081.xml --log-directory /ldw/apps/resin/log

          6734 Resin --root-directory /ldw/apps/resin/ -conf /ldw/conf/resin/resin-mms-webapp-28081.xml -server default -socketwait 15304 start --log-directory /ldw/apps/resin/log

    2)jstack -l pid > jstack1031.log命令打印棧信息,如果因某些原因無法成功打印,
         可以使用kill -3 pid,輸出到jvm日志中,resin服務器默認輸出到jvm-default.log日志中】
    3)查找占用CPU資源最高的進程id,使用top -H -p pid 查看進程pid的所有的線程,默認是按照%CPU高~低排序。
          或者直接使用top查看, shift+H顯示所有的線程,默認按照%CPU高~低排序。
          找到占用CPU利用率最高的pid,一般CPU利用率達到90%以上,將pid轉換為16進制,方法有很多種,我使用linux自帶python命令:hex(pid),很方便。
    4)根據轉換的16進制去jstack.log日志中查找基本能定位到具體哪行代碼的問題。
          "reportThirdException" daemon prio=10 tid=0x00007f8bd450b800 nid=0x12c4 runnable [0x00007f8b906ac000]
           java.lang.Thread.State: RUNNABLE
               at com.xxx.interfaces.util.NoticeMonitorSysHelper$ThreadStatue$1.run(NoticeMonitorSysHelper.java:167)
               at java.lang.Thread.run(Thread.java:722) 

    5)fix代碼,重新部署上線

          觀察cpu迅速降到正常值,swap值也降下來了,第二天觀察cpu、swap并沒有明顯的增加。

    6)在備機切換到線上機器前,通過jmap打印出JVM堆內存信息

           jmap -dump:live,format=b,file=heap1031.bin <pid>

     

    1212問題分析之內存泄漏

    12-11日晚VRS系統又一次服務Down掉,但是當時收到反饋后并沒有及時切到備機,未能及時保留問題現場,緊急重啟后暫時恢復服務,此時距離上一次上線間隔為9D。

    通過Zabbix監控來看swap內存這些天每天都在升高,最大值占用了接近4G,可服務器總內存不過才6G,初步定位肯定是Java應用內存泄漏導致。

    第二天一塊討論這塊問題如何排查,內存泄漏一般通過jstack輸出的棧很難定位到問題,只能對JVM堆內存信息做分析。

    這次問題也聯想到上次故障處理后,實際并沒有找到問題根本原因,想到了1031日存留過JVM堆信息heap1031.bin,然后下載到本地通過MAT(Eclipse插件)進行內存分析。也可以通過其他工具如jhat,但不如MAT直觀。

     

    問題定位過程:

    進入Eclipse:Memory analysis

    選擇File—》Open Head Dump…打開heap1031.bin

    會彈出一個對話框,選擇Leak Suspects Report 【自動檢測存疑的泄漏點,會報告出那些存活的對象以及這些對象沒有被gc的原因】

    MAT會自動分析出內存大致情況,直方圖顯示內存占用以及Problem Suspect

    通過以上會看到1635個JPEGImageReader實例沒有被釋放,可能這個是導致內存泄漏的根源,也說明跟系統裁圖功能有關,縮小了問題定位范圍。

    沒有釋放資源懷疑可能是IO流沒有正常關閉導致,因JVM堆棧轉存只看到底層代碼,具體還要進一步分析程序源代碼。

    下一步,點擊Details

    再點擊下面的Class Name,查看Inspector【顯示了當前顯示類或對象的詳細信息】

    通過Inspector能知道使用了javax.imageio.ImageReader接口,我們處理圖片的任務都在ImageResize.java類中,然后對這塊代碼進行分析排查。

    最初懷疑自動截圖這塊的影響,單獨對自動截圖功能做批量測試,循環截圖100,1000次dump內存看基本都沒有太大變化。

    代碼排查:

    try{

     //ImageReader聲稱能夠解碼指定格式  
     Iterator<ImageReader> it = ImageIO.getImageReadersByFormatName(ext);
     ImageReader reader = it.next();
     // 輸入源中的圖像將只按順序讀取 
     reader.setInput(iis, true);
     int srcWidth = reader.getWidth(0); // 源圖寬度
     int srcHeight = reader.getHeight(0); // 源圖高度
     if (srcWidth >= destWidth && srcHeight >= destHeight) {

        // 處理圖片...

        reader.dispose();

     }

    } catch (Exception e) {

      logger.error("Cut image failed, src_image_file:{}, error:{}, ", srcImageFile, e.getMessage(), e);
    } finally {

     // ...

    }


    從ImageReader入手查看代碼,發現調用了dispose方法,但是只在try中做了調用,finally中并沒有調用dispose方法。懷疑如果if條件不成立或者有異常發生,則不會調用dispose方法。

    查看下dispose方法的含義,如果不再使用這個ImageReader對象時,必須調用這個方法釋放資源;否則,可能導致資源(內存)無限的被占用。

    /**

         * Allows any resources held by this object to be released.  The

         * result of calling any other method (other than

         * <code>finalize</code>) subsequent to a call to this method

         * is undefined.

         *

         * <p>It is important for applications to call this method when they

         * know they will no longer be using this <code>ImageReader</code>.

         * Otherwise, the reader may continue to hold on to resources

         * indefinitely.

         *

         * <p>The default implementation of this method in the superclass does

         * nothing.  Subclass implementations should ensure that all resources,

         * especially native resources, are released.

         */

    public void dispose() {

    }


    找到這個原因時很興奮,所以我們將try中的reader.dispose()代碼注釋掉,直接做截圖測試,100,1000,然后打印JVM堆棧轉存用MAT分析,印證了上面的分析結果。

    然后修復這個Java類+log(不符合預期的log打印),部署上線了。

     

    因為已知道了JPEGImageReader實例未被釋放,故可通過命令jmap -histo:live <pid> | grep ImageReader 【jmap -histo:live <pid> 分析具體的對象數目和占用內存大小】

    在線上來查看JPEGImageReader instances數量變化,大概觀察1個小時左右,發現JPEGImageReader instances>5了,而且也沒有不符合條件的log輸出,正常應該釋放掉的,難道還是有內存泄漏?

    然后,繼續分析代碼,根據ImageReader搜索了下整個代碼庫,發現有個PgcAuditServiceImpl.java PGC審核里也有引用的代碼。

    Iterator<ImageReader> it = ImageIO.getImageReadersByFormatName(ext);
    reader = it.next();

    //這里沒有調用dispose()


    這塊僅使用了ImageReader獲取width和height,之后并沒有調用dispose方法,盡快修復重新上線。

    持續觀察一段時間,jmap查看類及對象情況:

    [root@cdn ~]# jmap -histo:live 28093 | grep ImageReader

    1905:             1             88  com.sun.imageio.plugins.gif.GIFImageReaderSpi

    1913:             1             88  com.sun.imageio.plugins.bmp.BMPImageReaderSpi

    1917:             1             88  com.sun.imageio.plugins.wbmp.WBMPImageReaderSpi

    1922:             1             88  com.sun.imageio.plugins.png.PNGImageReaderSpi

    1924:             1             88  com.sun.imageio.plugins.jpeg.JPEGImageReaderSpi

    2685:             2             48  com.sun.imageio.plugins.jpeg.JPEGImageReader$CallBackLock$State

    3881:             1             24  [Lcom.sun.imageio.plugins.jpeg.JPEGImageReader$CallBackLock$State;

    com.sun.imageio.plugins.jpeg.JPEGImageReader$CallBackLock$State,內部靜態類CallBackLock和State,所以有2個instances

    [Lcom.sun.imageio.plugins.jpeg.JPEGImageReader$CallBackLock$State; 1個Class對象

    持續觀察幾天性能指標平穩,服務器cpu、swap、load對于內存泄漏前占用都非常少了。

    經過以上分析,實際本次故障罪魁禍首是在PGC審核截圖引起。香港vrs因運營沒有使用到PGC審核功能所以也不會觸發內存泄漏問題。

     

    服務器性能指標前后變化情況:

    內存泄漏時內存使用情況:


    解決后內存使用情況:
     

    內存泄漏時CPU使用情況:

    解決后CPU使用情況:

     

    內存泄漏時Load性能:

    解決后Load性能:

     

    總結

    1)Java應用中的CPU 100%、內存泄漏兩種排錯方式以及具體命令,工具使用上面都已做了說明,可做參考。
    2)關注新的監控系統falcon將這些重要服務器性能指標加上監控,超過閾值告警。
    3)系統功能上線后,有意識的對服務器性能指標巡邏或許能提前發現異常并提早解決。
    4)更多詳細MAT使用,網上大量文章可參閱。
    5)建議使用Apache Commons Imaging替代Java自身的裁圖功能,可以避免顯示調用dispose釋放資源等問題。
    posted on 2016-12-22 23:01 David1228 閱讀(4616) 評論(2)  編輯  收藏 所屬分類: JAVAJ2EE性能優化

    FeedBack:
    # re: JAVA應用CPU占用100%|內存泄漏分析總結
    2017-10-18 10:25 | Jet Mah
    文章中的圖片都無法顯示了  回復  更多評論
      
    # re: JAVA應用CPU占用100%|內存泄漏分析總結
    2018-05-28 20:07 | David1228
    @Jet Mah
    這有可能是blogjava網站做了遷移,將圖片數據丟了,抽空我重新上傳下。謝謝關注  回復  更多評論
      

    <2017年10月>
    24252627282930
    1234567
    891011121314
    15161718192021
    22232425262728
    2930311234

    常用鏈接

    留言簿(4)

    隨筆分類

    隨筆檔案

    文章檔案

    新聞分類

    新聞檔案

    相冊

    收藏夾

    Java

    Linux知識相關

    Spring相關

    云計算/Linux/虛擬化技術/

    友情博客

    多線程并發編程

    開源技術

    持久層技術相關

    搜索

    •  

    積分與排名

    • 積分 - 358542
    • 排名 - 154

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 久久青草免费91线频观看不卡| 免费国产在线精品一区| 久久永久免费人妻精品| 狠狠综合久久综合88亚洲| caoporm超免费公开视频| 亚洲一区二区三区香蕉| 两个人看的www视频免费完整版| 国产亚洲精品AA片在线观看不加载| 免费视频精品一区二区| 亚洲一区二区高清| 中文字幕免费在线看电影大全 | 久久国产高潮流白浆免费观看| 狠狠色伊人亚洲综合成人| 精品人妻系列无码人妻免费视频| 区久久AAA片69亚洲| 污污网站18禁在线永久免费观看| 亚洲AV无码一区二区乱孑伦AS | 亚洲AV无码男人的天堂| 免费大黄网站在线观看| 2022国内精品免费福利视频| 亚洲AV无码一区东京热久久| 亚洲精品视频免费看| 亚洲乱码无人区卡1卡2卡3| 亚洲第一视频在线观看免费| 国产色无码精品视频免费| 亚洲视频在线一区二区三区| 性xxxx视频播放免费| 精品97国产免费人成视频| 亚洲视频一区二区在线观看| 四虎成人免费网址在线| 成人免费av一区二区三区| 亚洲日本国产乱码va在线观看| 精品无码国产污污污免费| 中国一级特黄高清免费的大片中国一级黄色片 | 亚洲国产精品国自产拍AV| 波多野结衣免费在线观看| 男女猛烈xx00免费视频试看| 亚洲国产a∨无码中文777| 国内免费高清在线观看| 中文字幕在线免费看| 在线观看日本亚洲一区|