<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Arthas排查jvm相關(guān)問題的利器

          共 4786字,需瀏覽 10分鐘

           ·

          2022-07-30 18:17

          背景:

          一次線上問題的綜合排查排查,兩個(gè)相同的系統(tǒng)的某個(gè)模塊,數(shù)據(jù)量更少的系統(tǒng)查詢更慢。
          先說下整體思路:

          1. 查看系統(tǒng)整理負(fù)載,網(wǎng)絡(luò)有100左右毫秒的延遲,看起來影響不大


          2. 查看正序運(yùn)行整體情況,一次查詢會(huì)經(jīng)歷3次FGC,有問題,解決后雖然會(huì)快一些但是還是有點(diǎn)慢

          3. 跟蹤調(diào)用棧,發(fā)現(xiàn)有點(diǎn)在獲查詢結(jié)果的時(shí)候特別慢

          4. 排查是否有mysql慢查詢(定義為1秒以上的查詢),結(jié)果是沒有

          5. 通過arthas發(fā)現(xiàn)調(diào)用了20多次查詢,每次網(wǎng)絡(luò)延遲100ms,加起來就有2s了,定位出問題。

          這樣看起來arthas真的很強(qiáng)大,它不僅僅能處理上述問題,還能….

          • 這個(gè)類從哪個(gè) jar 包加載的?為什么會(huì)報(bào)各種類相關(guān)的 Exception?

          • 我改的代碼為什么沒有執(zhí)行到?難道是我沒 commit?分支搞錯(cuò)了?

          • 遇到問題無法在線上 debug,難道只能通過加日志再重新發(fā)布嗎?

          • 線上遇到某個(gè)用戶的數(shù)據(jù)處理有問題,但線上同樣無法 debug,線下無法重現(xiàn)!

          • 是否有一個(gè)全局視角來查看系統(tǒng)的運(yùn)行狀況?

          • 有什么辦法可以監(jiān)控到JVM的實(shí)時(shí)運(yùn)行狀態(tài)?

          • 代碼出現(xiàn)異常,怎么能獲取請(qǐng)求參數(shù)和返回值。

          Arthas到底是什么

          Arthas 是Alibaba開源的Java診斷工具,采用命令行交互模式,提供了豐富的功能,是排查jvm相關(guān)問題的利器。
          在逛github時(shí),發(fā)現(xiàn)了這款利器,深入了解之后,簡直驚為天人。下面先列舉一下它能做的一些事情:

          • 提供性能看板,包括線程、cpu、內(nèi)存等信息,并且會(huì)定時(shí)的刷新。

          • 根據(jù)各種條件查看線程快照。比如找出cpu占用率最高的n個(gè)線程等

          • 輸出jvm的各種信息,如gc算法、jdk版本、ClassPath等

          • 查看/設(shè)置sysprop和sysenv

          • 查看某個(gè)類的靜態(tài)屬性,也可以通過ognl語法執(zhí)行一些語句

          • 查看已加載的類的詳細(xì)信息,比如這個(gè)類從哪個(gè)jar包加載的。也可以查看類的方法的信息

          • dump某個(gè)類的字節(jié)碼到指定目錄

          • 直接反編譯指定的類

          • 查看類加載器的一些信息

          • 可以讓jvm重新加載某個(gè)類

          • 監(jiān)控方法的執(zhí)行,同時(shí)可以獲取到執(zhí)行的入?yún)?、出參以及拋出的異?/p>

          • 追蹤方法執(zhí)行的調(diào)用棧,以及各個(gè)方法的調(diào)用時(shí)間

          Arthas運(yùn)行原理

          Arthas命令列表

          athas的各個(gè)命令

          sc 和 sm

          • 通過sc可以查看已加載類的相關(guān)信息,比如該類是從哪個(gè)jar包加載的,被哪個(gè)類加載器加載的,以及是否是接口等等。

          • sm查看已加載類的方法詳情。

          dashboard

          進(jìn)入當(dāng)前系統(tǒng)的實(shí)時(shí)數(shù)據(jù)面板,按 ctrl+c 退出。這個(gè)面板會(huì)實(shí)時(shí)刷新,其中包括線程信息、內(nèi)存信息、gc信息、還有一些運(yùn)行時(shí)的數(shù)據(jù)。
          另外,當(dāng)運(yùn)行在Ali-tomcat時(shí),會(huì)顯示當(dāng)前tomcat的實(shí)時(shí)信息,如HTTP請(qǐng)求的qps, rt, 錯(cuò)誤數(shù), 線程池信息等等。

          thread

          通過thread命令可以查看當(dāng)前jvm進(jìn)程的線程詳情??梢圆榭淳€程的cpu使用時(shí)間占比,通過指定各種參數(shù)可以找出最忙的幾個(gè)線程,以及阻塞其他線程的線程。具體如何使用這里不多做介紹,大家可以去看arthas的官方文檔。


          1
          2
          3
          當(dāng)前最忙的前N個(gè)線程并打印堆棧
          thread -i 5000
          thread -i 5000


          jvm

          通過jvm命令直接輸出當(dāng)前jvm的各種信息。

          getstatic

          通過getstatic命令可以方便的查看類的靜態(tài)屬性。


          1
          getstatic demo.MahtGame random


          sysprop和sysenv

          • 通過sysprop可以查看所有的系統(tǒng)變量,也可以設(shè)置某個(gè)系統(tǒng)變量。

          • 同理,通過sysenv可以查看所有的操作系統(tǒng)環(huán)境變量,也可以查看設(shè)置某個(gè)環(huán)境變量。

          ognl

          執(zhí)行ognl表達(dá)式,可執(zhí)行任意代碼


          1
          Ognl @demo.MathGame@random


          動(dòng)態(tài)修改日志級(jí)別

          1. 通過ognl獲取對(duì)應(yīng)類上的logger對(duì)象實(shí)現(xiàn)類

          2. sc命令來查看具體從哪個(gè)jar包里加載的,sc -d org.apache.log4j.Logger

          3. 通過ognl修改日志級(jí)別

          更詳細(xì)的介紹:https://github.com/alibaba/arthas/issues/11

          dump

          將已加載類的字節(jié)碼dump到本地磁盤上。

          jad

          有時(shí)我們經(jīng)常會(huì)不確定線上或者測試環(huán)境的包是否是我們修改過的,這時(shí)候就可以通過jad反編譯來看下。


          1
          反編譯指定已加載類的源碼,jad demo.MathGame


          classloader

          將 JVM 中所有的classloader的信息統(tǒng)計(jì)出來,并可以展示繼承樹,urls等。

          redafine

          該命令可以加載外部的.class文件,然后覆蓋 jvm已加載的類。注意,這個(gè)命令不一定都能覆蓋成功,如果添加了新的field,就不會(huì)加載成功。

          關(guān)于redefine,arthas的github上有個(gè)非常經(jīng)典的userCase:

          https://github.com/alibaba/arthas/issues/263

          動(dòng)態(tài)更新代碼,不用重啟jvm

          watch

          • 讓你能方便的觀察到指定方法的調(diào)用情況。能觀察到的范圍為:返回值、拋出異常、入?yún)ⅲㄟ^編寫 OGNL 表達(dá)式進(jìn)行對(duì)應(yīng)變量的查看。

          • watch的使用姿勢比較豐富,可以在四個(gè)不同的場景觀察方法的執(zhí)行。比如方法調(diào)用之前、方法調(diào)用之后、方法異常之后、方法結(jié)束之后。默認(rèn)觀察的是方法結(jié)束之后。

          • 如果觀察的是方法結(jié)束之后的場景,由于入?yún)⒖赡茉趫?zhí)行方法時(shí)被改變,所以此時(shí)輸出的可能不是真正的入?yún)ⅰR虼?,要看真正的入?yún)ⅲ捶椒ㄕ{(diào)用之前的,也就是加上-b的參數(shù)。

          • 另外,使用-b參數(shù)觀察的話,則觀察不到方法返回的結(jié)果以及拋出的異常了。

          參數(shù)名稱參數(shù)說明
          class-pattern類名表達(dá)式匹配
          method-pattern方法名表達(dá)式匹配
          express觀察表達(dá)式
          condition-express條件表達(dá)式
          [b]在方法調(diào)用之前觀察
          [e]在方法異常之后觀察
          [s]在方法返回之后觀察
          [f]在方法結(jié)束之后(正常返回和異常返回)觀察
          [E]開啟正則表達(dá)式匹配,默認(rèn)為通配符匹配
          [x:]指定輸出結(jié)果的屬性遍歷深度,默認(rèn)為 1
          [n:]只執(zhí)行n次,默認(rèn)會(huì)不斷輸出,除非用戶按下cltr+c


          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          # 觀察CommonTest的test方法
          # 輸出 入?yún)ⅰ⒎祷亟Y(jié)果、拋出的異常 —— 輸出的內(nèi)容可以動(dòng)態(tài)調(diào)整
          # 后面跟著的是 條件表達(dá)式,表示耗時(shí)超過10ms才輸出
          # -n 表示只執(zhí)行一次,-x表示 入?yún)⒑头祷亟Y(jié)果的展開層次為5層
          watch *.CommonTest test "{params,returnObj,throwExp}" '#cost>10' -x 5 -n 1

          # 耗時(shí)大于10ms并且第一個(gè)參數(shù)等于1才輸出
          watch *.CommonTest test "{params,returnObj,throwExp}" '#cost>10 && params[0]==1' -x 5 -n 1
          # 第一個(gè)參數(shù)大于1 并且第二個(gè)參數(shù)等于hello才輸出
          watch *.CommonTest test "{params,returnObj,throwExp}" 'params[0]>1 && params[1]=="hello"' -x 5 -n 1
          # 第一個(gè)參數(shù)小于5或者第二個(gè)參數(shù)等于"world"就輸出
          watch *.CommonTest test "{params,returnObj,throwExp}" 'params[0]<5 || params[1]=="wolrd"' -x 5 -n 1
          # 第一個(gè)參數(shù)的name字段等于world時(shí)才輸出。
          # 由于在方法執(zhí)行過程中參數(shù)的name屬性可能發(fā)生改變,因此加上-b才能觀察到真正的入?yún)?br>watch -b *.CommonTest test "{params,returnObj,throwExp}" 'params[0].name=="wolrd"' -x 5 -n 1

          # 由于同時(shí)指定了-s和-b,所以方法被調(diào)用一次,就會(huì)輸出2次結(jié)果(兩個(gè)場景分開輸出),分別是方法被調(diào)用前,和返回之后
          # 注意,這里如果-n只設(shè)置成1,那么只會(huì)輸出-b對(duì)應(yīng)的輸出,-s對(duì)應(yīng)的輸出由于沒有次數(shù)了就無法輸出了
          watch *.CommonTest test '{params,returnObj,throwExp}' -x 5 -n 2 -s -b


          在填寫條件表達(dá)式時(shí)要注意一點(diǎn),條件表達(dá)式中的params默認(rèn)都是獲取的方法執(zhí)行完后的參數(shù)信息,比如入?yún)的屬性name方法執(zhí)行前是”hello”,在方法執(zhí)行后變成了”world”,那么條件表達(dá)式傳入’params[0].name=”hello”‘將不會(huì)輸出,只有填入’params[0].name=”hello”‘才可以匹配上。這點(diǎn)對(duì)于后面的trace、stack命令也是一樣的。

          查看方法輸入?yún)?shù)/返回值/異常信息,watch demo.MathGame primeFactors “{params,returnObj}” -x 2

          monitor

          monitor命令可以監(jiān)控方法的執(zhí)行情況。比如調(diào)用成功次數(shù),失敗次數(shù),失敗率、平均執(zhí)行時(shí)間等等。默認(rèn)120秒輸出一次,也就是說,當(dāng)我們輸入monitor命令之后,每120秒就會(huì)輸出一次統(tǒng)計(jì)結(jié)果。

          通過-c參數(shù)可以修改輸出頻率,支持通配符和正則表達(dá)式。
          monitor -c 5 demo.MathGame primeFactors

          trace

          方法內(nèi)部調(diào)用路徑,并輸出方法路徑上的每個(gè)節(jié)點(diǎn)上耗時(shí),tt命令會(huì)記錄每次方法調(diào)用的各種信息。它和watch有些相似但是它能記錄下各個(gè)時(shí)間點(diǎn)的調(diào)用信息,之后隨時(shí)查看,甚至replay這次調(diào)用。


          1
          trace demo.MathGame run


          tt

          timetunnel,記錄下指定方法每次調(diào)用的入?yún)⒑头祷匦畔ⅲ⒛軐?duì)這些不同的時(shí)間下調(diào)用進(jìn)行觀測,同時(shí)可回放該方法調(diào)用
          tt -t demo.MathGame primeFactors

          直接重放請(qǐng)求參數(shù)


          1
          2
          1.使用tt –t 類名次 方法名次
          2.tt –play -i 1000



          另外介紹幾個(gè)我經(jīng)常用的工具,jmap,jstat,jstack,dump這些基本的就不介紹了。

          Tprofiler

          TProfiler是一個(gè)可以在生產(chǎn)環(huán)境長期使用的性能分析工具.它同時(shí)支持剖析和采樣兩種方式,記錄方法執(zhí)行的時(shí)間和次數(shù),生成方法熱點(diǎn) 對(duì)象創(chuàng)建熱點(diǎn) 線程狀態(tài)分析等數(shù)據(jù),為查找系統(tǒng)性能瓶頸提供數(shù)據(jù)支持.

          TProfiler在JVM啟動(dòng)時(shí)把時(shí)間采集程序注入到字節(jié)碼中,整個(gè)過程無需修改應(yīng)用源碼.運(yùn)行時(shí)會(huì)把數(shù)據(jù)寫到日志文件,一般情況下每小時(shí)輸出的日志小于50M.

          show-busy-java-threads

          • 查找cpu性能消耗過程
            top命令找出消耗CPU高的Java進(jìn)程及其線程id:
            開啟線程顯示模式(top -H,或是打開top后按H)
            按CPU使用率排序(top缺省是按CPU使用降序,已經(jīng)合要求;打開top后按P可以顯式指定按CPU使用降序)
            記下Java進(jìn)程id及其CPU高的線程id

          • 查看消耗CPU高的線程棧:
            用進(jìn)程id作為參數(shù),jstack出有問題的Java進(jìn)程
            手動(dòng)轉(zhuǎn)換線程id成十六進(jìn)制(可以用printf %x 1234)
            在jstack輸出中查找十六進(jìn)制的線程id(可以用vim的查找功能/0x1234,或是grep 0x1234 -A 20)

          • 查看對(duì)應(yīng)的線程棧,分析問題
            查問題時(shí),會(huì)要多次上面的操作以分析確定問題,這個(gè)過程太繁瑣太慢了。

          • 參考:https://blog.csdn.net/u013332124/article/details/84888074#11_redefine_157

          瀏覽 200
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  黄片免费视频在线观看 | 免费毛片看片 | 一区二区无码专区 | 日韩欧美一本 | 影音先锋在线播放99av |