乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      一次線上問題排查所引發(fā)的思考

       xkl135 2018-08-03


      前言

      直到有一天你會碰到線上奇奇怪怪的問題,如:

      • 線程執(zhí)行一個任務(wù)遲遲沒有返回,應(yīng)用假死。

      • 接口響應(yīng)緩慢,甚至請求超時。

      • CPU 高負(fù)載運行。

      這類問題并不像一個空指針、數(shù)組越界這樣明顯好查,這時就需要剛才提到的內(nèi)存模型、對象創(chuàng)建、線程等相關(guān)知識結(jié)合在一起來排查問題了。

      正好這次借助之前的一次生產(chǎn)問題來聊聊如何排查和解決問題。

      生產(chǎn)現(xiàn)象

      首先看看問題的背景吧:

      我這其實是一個定時任務(wù),在固定的時間會開啟 N 個線程并發(fā)的從 Redis 中獲取數(shù)據(jù)進(jìn)行運算。

      業(yè)務(wù)邏輯非常簡單,但應(yīng)用一般涉及到多線程之后再簡單的事情都要小心對待。

      果不其然這次就出問題了。

      現(xiàn)象:原本只需要執(zhí)行幾分鐘的任務(wù)執(zhí)行了幾個小時都沒退出。翻遍了所有的日志都沒找到異常。

      于是便開始定位問題之路。

      定位問題

      既然沒辦法直接從日志中發(fā)現(xiàn)異常,那就只能看看應(yīng)用到底在干嘛了。

      最常見的工具就是 JDK 自帶的那一套。

      這次我使用了 jstack 來查看線程的執(zhí)行情況,它的作用其實就是 dump 當(dāng)前的線程堆棧。

      當(dāng)然在 dump 之前是需要知道我應(yīng)用的 pid 的,可以使用 jps -v 這樣的方式列出所有的 Java 進(jìn)程。

      當(dāng)然如果知道關(guān)鍵字的話直接使用 ps aux|grep java 也是可以的。

      拿到 pid=1523 了之后就可以利用 jstack 1523 > 1523.log 這樣的方式將 dump 文件輸出到日志文件中。

      如果應(yīng)用簡單不復(fù)雜,線程這些也比較少其實可以直接打開查看。

      但復(fù)雜的應(yīng)用導(dǎo)出來的日志文件也比較大還是建議用專業(yè)的分析工具。

      我這里的日志比較少直接打開就可以了。

      因為我清楚知道應(yīng)用中開啟的線程名稱,所以直接根據(jù)線程名就可以在日志中找到相關(guān)的堆棧:



      所以通常建議大家線程名字給的有意義,在排查問題時很有必要。

      其實其他幾個線程都和這里的堆棧類似,很明顯的看出都是在做 Redis 連接。

      于是我登錄 Redis 查看了當(dāng)前的連接數(shù),發(fā)現(xiàn)已經(jīng)非常高了。

      這樣 Redis 的響應(yīng)自然也就變慢了。

      接著利用 jps -v 列出了當(dāng)前所以在跑的 Java 進(jìn)程,果不其然有好幾個應(yīng)用都在查詢 Redis,而且都是并發(fā)連接,問題自然就找到了。

      解決辦法

      所以問題的主要原因是:大量的應(yīng)用并發(fā)查詢 Redis,導(dǎo)致 Redis 的性能降低。

      既然找到了問題,那如何解決呢?

      • 減少同時查詢 Redis 的應(yīng)用,分開時段降低 Redis 的壓力。

      • 將 Redis 復(fù)制幾個集群,各個應(yīng)用分開查詢。但是這樣會涉及到數(shù)據(jù)的同步等運維操作,或者由程序了進(jìn)行同步也會增加復(fù)雜度。

      目前我們選擇的是第一個方案,效果很明顯。

      本地模擬

      上文介紹的是線程相關(guān)問題,現(xiàn)在來分析下內(nèi)存的問題。

      以這個類為例:

      https://github.com/crossoverJie/Java-Interview/blob/master/src/main/java/com/crossoverjie/oom/heap/HeapOOM.java

      1public class HeapOOM {
      2
      3    public static void main(String[] args) {
      4        List<String> list = new ArrayList<>(10) ;
      5        while (true){
      6            list.add('1') ;
      7        }
      8    }
      9}

      啟動參數(shù)如下:

      1-Xms20m
      2-Xmx20m
      3-XX: HeapDumpOnOutOfMemoryError
      4-XX:HeapDumpPath=/Users/xx/Documents

      為了更快的突出內(nèi)存問題將堆的最大內(nèi)存固定在 20M,同時在 JVM 出現(xiàn) OOM 的時候自動 dump 內(nèi)存到 /Users/xx/Documents(不配路徑則會生成在當(dāng)前目錄)。

      執(zhí)行之后果不其然出現(xiàn)了異常:



      同時對應(yīng)的內(nèi)存 dump 文件也生成了。

      內(nèi)存分析

      這時就需要相應(yīng)的工具進(jìn)行分析了,最常用的自然就是 MAT 了。

      我試了一個在線工具也不錯(文件大了就不適合了):

      http:///index.jsp

      上傳剛才生成的內(nèi)存文件之后:



      因為是內(nèi)存溢出,所以主要觀察下大對象:



      也有相應(yīng)提示,這個很有可能就是內(nèi)存溢出的對象,點進(jìn)去之后:



      看到這個堆棧其實就很明顯了:

      在向 ArrayList 中不停的寫入數(shù)據(jù)時,會導(dǎo)致頻繁的擴(kuò)容也就是數(shù)組復(fù)制這些過程,最終達(dá)到 20M 的上限導(dǎo)致內(nèi)存溢出了。

      更多建議

      上文說過,一旦使用了多線程,那就要格外小心。

      以下是一些日常建議:

      • 盡量不要在線程中做大量耗時的網(wǎng)絡(luò)操作,如查詢數(shù)據(jù)庫(可以的話在一開始就將數(shù)據(jù)從從 DB 中查出準(zhǔn)備好)。

      • 盡可能的減少多線程競爭鎖。可以將數(shù)據(jù)分段,各個線程分別讀取。

      • 多利用 CAS 自旋 的方式更新數(shù)據(jù),減少鎖的使用。

      • 應(yīng)用中加上 -XX: HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp 參數(shù),在內(nèi)存溢出時至少可以拿到內(nèi)存日志。

      • 線程池監(jiān)控。如線程池大小、隊列大小、最大線程數(shù)等數(shù)據(jù),可提前做好預(yù)估。

      • JVM 監(jiān)控,可以看到堆內(nèi)存的漲幅趨勢,GC 曲線等數(shù)據(jù),也可以提前做好準(zhǔn)備。

      總結(jié)

      線上問題定位需要綜合技能,所以是需要一些基礎(chǔ)技能。如線程、內(nèi)存模型、Linux 等。

      當(dāng)然這些問題沒有實操過都是紙上談兵;如果第一次碰到線上問題,不要慌張,反而應(yīng)該慶幸解決之后你又會習(xí)得一項技能。

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多