<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>

          帶著8個(gè)問題5分鐘教你學(xué)會(huì) Arthas 診斷工具

          共 9786字,需瀏覽 20分鐘

           ·

          2021-12-09 13:52

          點(diǎn)擊關(guān)注公眾號(hào),Java干貨及時(shí)送達(dá)??


          前言

          Arthas?是Alibaba開源的Java診斷工具,深受開發(fā)者喜愛。

          當(dāng)你遇到以下類似問題而束手無策時(shí),Arthas可以幫助你解決:

          1. 這個(gè)類從哪個(gè) jar 包加載的?為什么會(huì)報(bào)各種類相關(guān)的 Exception?
          2. 我改的代碼為什么沒有執(zhí)行到?難道是我沒 commit?分支搞錯(cuò)了?
          3. 遇到問題無法在線上 debug,難道只能通過加日志再重新發(fā)布嗎?
          4. 線上遇到某個(gè)用戶的數(shù)據(jù)處理有問題,但線上同樣無法 debug,線下無法重現(xiàn)!
          5. 是否有一個(gè)全局視角來查看系統(tǒng)的運(yùn)行狀況?
          6. 有什么辦法可以監(jiān)控到JVM的實(shí)時(shí)運(yùn)行狀態(tài)?
          7. 怎么快速定位應(yīng)用的熱點(diǎn),生成火焰圖?
          8. 怎樣直接從JVM內(nèi)查找某個(gè)類的實(shí)例?

          這 8 個(gè)問題,Arthas 官方文檔(https://arthas.aliyun.com/doc)中并沒有給出答案或標(biāo)準(zhǔn)的解決方案。

          坑爹啊

          這不是管殺不管埋嗎?。?!

          管殺不管埋

          正文

          「下面是筆者結(jié)合多年使用 Arthas 的經(jīng)驗(yàn),針對(duì)這 8 個(gè)問題給出的詳細(xì)解決方案,如果有疑問歡迎評(píng)論區(qū)指出?!?/strong>

          準(zhǔn)備

          先給出我的測(cè)試代碼

          package?com.shockang.study;

          import?com.alibaba.fastjson.JSON;
          import?lombok.AccessLevel;
          import?lombok.Getter;
          import?lombok.Setter;
          import?lombok.ToString;
          import?lombok.experimental.FieldDefaults;

          import?java.util.List;
          import?java.util.concurrent.TimeUnit;

          public?class?ArthasDemo?{
          ????public?static?void?main(String[]?args)?{
          ????????String?s?=?"[{\"name\":\"zhangsan\",\"age\":\"10\",\"telephone\":\"123456\",\"interests\":[\"sing\",\"dance\",\"rap\"]},\n"?+
          ????????????????"{\"name\":\"lisi\",\"age\":\"20\",\"telephone\":\"123457\",\"interests\":[\"sing\",\"swim\"]},\n"?+
          ????????????????"{\"name\":\"wangwu\",\"age\":\"30\",\"telephone\":\"123458\",\"interests\":[\"sing\",\"program\"]}]";
          ????????//模擬一遍遍的調(diào)用方法的過程
          ????????for?(;?;?)?{
          ????????????System.out.println(new?ArthasDemo().convert(s));
          ????????????try?{
          ????????????????TimeUnit.SECONDS.sleep(10);
          ????????????}?catch?(InterruptedException?e)?{
          ????????????????e.printStackTrace();
          ????????????}
          ????????}
          ????}

          ????private?List?convert(String?s)?{
          ????????return?JSON.parseArray(s,?People.class);
          ????}


          ????@Getter
          ????@Setter
          ????@ToString
          ????@FieldDefaults(level?=?AccessLevel.PRIVATE)
          ????private?static?class?People?{
          ????????/**
          ?????????*?姓名
          ?????????*/

          ????????String?name;
          ????????/**
          ?????????*?年齡
          ?????????*/

          ????????String?age;
          ????????/**
          ?????????*?電話
          ?????????*/

          ????????String?telephone;
          ????????/**
          ?????????*?興趣列表
          ?????????*/

          ????????List?interests;
          ????}
          }

          以下是控制臺(tái)正常打印的結(jié)果

          /Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/bin/java ...
          [ArthasDemo.People(name=zhangsan, age=10, telephone=123456, interests=[sing, dance, rap]), ArthasDemo.People(name=lisi, age=20, telephone=123457, interests=[sing, swim]), ArthasDemo.People(name=wangwu, age=30, telephone=123458, interests=[sing, program])]
          [ArthasDemo.People(name=zhangsan, age=10, telephone=123456, interests=[sing, dance, rap]), ArthasDemo.People(name=lisi, age=20, telephone=123457, interests=[sing, swim]), ArthasDemo.People(name=wangwu, age=30, telephone=123458, interests=[sing, program])]

          下載并運(yùn)行 Arthas

          按照下圖中的步驟,選擇一個(gè) Java 進(jìn)程進(jìn)行 attach。

          下載并運(yùn)行Arthas

          訪問 WebConsole

          attach 成功后可以打開谷歌瀏覽器輸入http://127.0.0.1:3658/?打開 WebConsole

          (吐槽一句 Mac OS 的 Safari 瀏覽器不支持)

          ?

          使用 WebConsole 最方便的是你可以打開多個(gè)標(biāo)簽頁(yè)同時(shí)操作

          ?

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

          這個(gè)問題我經(jīng)常在處理各種「依賴沖突」的時(shí)候遇到,有一些類的完全名稱是一模一樣,通過常規(guī)的辦法無法解決類具體從哪個(gè) jar 包加載。

          別急,看我下面的解決辦法。

          1. sc

          通過?sc?命令 模糊查看當(dāng)前 JVM 中是否加載了包含關(guān)鍵字的類,以及獲取其完全名稱。

          ?

          注意使用?sc -d?命令,獲取 classLoaderHash,這個(gè)值在后面需要用到。

          ?
          sc?-d?*ArthasDemo*

          sc-d命令
          1. classloader

          通過?classloader?查看 class 文件來自哪個(gè) jar 包

          ?

          使用?cls?命令可以清空命令行,這個(gè)簡(jiǎn)單的命令官方文檔居然找不到。。。

          ?
          ?

          注意?classloader -c?后面的值填上面第一步中獲取到的 Hash 值,class 文件路徑使用'/'分割,且必須以.class 結(jié)尾。

          ?
          [arthas@3633]$?classloader?-c?18b4aac2?-r?com/shockang/study/ArthasDemo.class
          file:/Users/shockang/code/concurrentbook/target/classes/com/shockang/study/ArthasDemo.class
          Affect(row-cnt:1)?cost?in?0?ms.

          上面是顯示 class 文件路徑的,如果 class 文件來自 jar 包,可以顯示 jar 包路徑,例如官方文檔給的例子:

          $?classloader?-c?1b6d3586?-r?java/lang/String.class
          jar:file:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/rt.jar!/java/lang/String.class

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

          推薦使用?watch?和?tt?命令,非常好用。

          這兩個(gè)命令都是用來查看方法調(diào)用過程的,不同的是?watch?命令是調(diào)用一次打印一次方法的調(diào)用情況,而?tt?命令可以先生成一個(gè)不斷增加的調(diào)用列表,然后指定其中某一項(xiàng)進(jìn)行觀測(cè)。

          1. 使用?watch?命令查看方法調(diào)用情況。我們要查看 ArthasDemo 這個(gè)類里面的 convert 方法調(diào)用情況。
          watch命令
          watch?com.shockang.study.ArthasDemo?convert?"{params,target,returnObj}"?-f?-x?4

          watch?后面跟上完全類名和方法名,以及一個(gè) OGNL 的表達(dá)式,-f 表示不論正常返回還是異常返回都進(jìn)行觀察,-x 表示輸出結(jié)果的屬性遍歷深度,默認(rèn)為 1,

          ?

          建議無腦寫 4 就行,這是筆者經(jīng)驗(yàn)來看最大的遍歷深度,再大就不支持了

          ?
          1. 使用?tt?命令來觀測(cè)方法調(diào)用情況,tt?命令可以查看「多次調(diào)用」并選擇其中一個(gè)進(jìn)行觀測(cè),但是如果輸出結(jié)果是多層嵌套就沒辦法看了,而?watch?可以查看「多層嵌套」的結(jié)果。
          ?

          使用 tt -t 記錄下當(dāng)前方法的每次調(diào)用環(huán)境現(xiàn)場(chǎng)

          ?
          tt -t命令
          tt?-t?com.shockang.study.ArthasDemo?convert

          TIMESTAMP表示方法調(diào)用發(fā)生的時(shí)間,COST 表示調(diào)用耗時(shí)(ms),IS-RET表示是否正常返回,IS-EXP 表示是否異常返回,OBJECT 表示對(duì)象的 HASH 值

          ?

          對(duì)于具體一個(gè)時(shí)間片的信息而言,你可以通過 -i 參數(shù)后邊跟著對(duì)應(yīng)的 INDEX 編號(hào)查看到他的詳細(xì)信息

          ?
          tt-i命令
          ?

          圖中之所以可以打印興趣列表,是調(diào)用了其 toString 方法,如果沒有重寫 java.lang.Object 類的 toString 方法,只會(huì)看到 hash 值。

          ?
          1. 如何判斷代碼是否已經(jīng)提交?

          通過?jad --source-only?可以查看源代碼。

          [arthas@3633]$?jad?--source-only?com.shockang.study.ArthasDemo
          ???????/*
          ????????*?Decompiled?with?CFR.
          ????????*/
          ???????package?com.shockang.study;

          ???????import?com.alibaba.fastjson.JSON;
          ???????import?java.util.List;
          ???????import?java.util.concurrent.TimeUnit;

          ???????public?class?ArthasDemo?{
          ???????????public?static?void?main(String[]?args)?{
          /*15*/?????????String?s?=?"[{\"name\":\"zhangsan\",\"age\":\"10\",\"telephone\":\"123456\",\"interests\":[\"sing\",\"dance\",\"rap\"]},\n{\"name\":\"lisi\",\"age\":\"20
          \",\"telephone\":\"123457\",\"interests\":[\"sing\",\"swim\"]},\n{\"name\":\"wangwu\",\"age\":\"30\",\"telephone\":\"123458\",\"interests\":[\"sing\",\"program\"]}]";
          ???????????????while?(true)?{
          /*20*/?????????????System.out.println(new?ArthasDemo().convert(s));
          ???????????????????try?{
          /*22*/?????????????????TimeUnit.SECONDS.sleep(10L);
          /*25*/?????????????????continue;
          ???????????????????}
          ???????????????????catch?(InterruptedException?e)?{
          /*24*/?????????????????e.printStackTrace();
          ???????????????????????continue;
          ???????????????????}
          ???????????????????break;
          ???????????????}
          ???????????}

          ???????????private?List?convert(String?s)?{
          /*30*/?????????return?JSON.parseArray(s,?People.class);
          ???????????}

          ???????????private?static?class?People?{
          ???????????????private?String?name;
          ???????????????private?String?age;
          ???????????????private?String?telephone;
          ???????????????private?List?interests;

          ???????????????private?People()?{
          ???????????????}

          ???????????????public?String?toString()?{
          ???????????????????return?"ArthasDemo.People(name="?+?this.getName()?+?",?age="?+?this.getAge()?+?",?telephone="?+?this.getTelephone()?+?",?interests="?+?this.getIntere
          sts()?+?")";
          ???????????????}

          ???????????????public?String?getName()?{
          ???????????????????return?this.name;
          ???????????????}

          ???????????????public?void?setName(String?name)?{
          ???????????????????this.name?=?name;
          ???????????????}

          ???????????????public?String?getAge()?{
          ???????????????????return?this.age;
          ???????????????}

          ???????????????public?String?getTelephone()?{
          ???????????????????return?this.telephone;
          ???????????????}

          ???????????????public?List?getInterests()?{
          ???????????????????return?this.interests;
          ???????????????}

          ???????????????public?void?setAge(String?age)?{
          ???????????????????this.age?=?age;
          ???????????????}

          ???????????????public?void?setTelephone(String?telephone)?{
          ???????????????????this.telephone?=?telephone;
          ???????????????}

          ???????????????public?void?setInterests(List?interests)?{
          ???????????????????this.interests?=?interests;
          ???????????????}
          ???????????}
          ???????}

          [arthas@3633]$

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

          通過上面問題 2 的?watch?和?tt?命令可以查看方法調(diào)用情況。

          此外,可以通過?redefine?命令「熱替換」線上的代碼,注意應(yīng)用重啟之后會(huì)失效,這在某些緊急情況下會(huì)有奇效。

          比如說我們修改一下方法體里面的代碼,加了一行日志打印:

          ????private?List?convert(String?s)?{
          ????????System.out.println(s);
          ????????return?JSON.parseArray(s,?People.class);
          ????}

          這時(shí)我們就可以將新代碼編譯后的 class 文件熱替換正在運(yùn)行的 ArthasDemo 的代碼。

          redefine命令
          熱替換 JVM 內(nèi)存中(方法區(qū))加載的類

          從這張圖可以明顯的看出,明明源碼中沒有打印字符串 s 的邏輯,但是控制臺(tái)還是打印了字符串,因?yàn)槲覀円呀?jīng)熱替換了 JVM 內(nèi)存中(方法區(qū))加載的類。

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

          這個(gè)問題沒有完美的解決辦法

          參考一下問題 2 和問題 3的解決方案

          推薦使用?tt?命令并將命令行返回結(jié)果輸出到一個(gè)文件中,后續(xù)可以選擇異常的一行記錄使用?tt -i?命令進(jìn)行深入的分析。

          tee指令會(huì)從標(biāo)準(zhǔn)輸入設(shè)備讀取數(shù)據(jù),將其內(nèi)容輸出到標(biāo)準(zhǔn)輸出設(shè)備,同時(shí)保存成文件。

          tee命令
          tt?-t?com.shockang.study.ArthasDemo?convert?|?tee?/Users/shockang/Downloads/log

          此外還可以使用?monitor?命令統(tǒng)計(jì)方法調(diào)用成功失敗情況。

          monitor命令
          monitor?-c?30?com.shockang.study.ArthasDemo?convert?|?tee?/Users/shockang/Downloads/log1
          ?

          -c 后面接統(tǒng)計(jì)周期,默認(rèn)值為120秒

          ?

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

          使用?dashboard?命令可以查看當(dāng)前系統(tǒng)的實(shí)時(shí)數(shù)據(jù)面板, 當(dāng)運(yùn)行在Ali-tomcat時(shí),會(huì)顯示當(dāng)前tomcat的實(shí)時(shí)信息,如HTTP請(qǐng)求的qps, rt, 錯(cuò)誤數(shù), 線程池信息等等。

          dashboard實(shí)時(shí)數(shù)據(jù)面板

          從圖中可以看到線程情況,內(nèi)存使用情況,系統(tǒng)參數(shù)等。

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

          使用?jvm?命令可以查看 JVM 的實(shí)時(shí)運(yùn)行狀態(tài)。

          JVM 的實(shí)時(shí)運(yùn)行狀態(tài)

          問題 7:怎么快速定位應(yīng)用的熱點(diǎn),生成火焰圖?

          profiler?命令支持生成應(yīng)用熱點(diǎn)的火焰圖。本質(zhì)上是通過不斷的采樣,然后把收集到的采樣結(jié)果生成火焰圖。

          ?

          默認(rèn)情況下,生成的是 cpu 的火焰圖,即 event 是 cpu,可以用--event 參數(shù)來指定。注意不同系統(tǒng)支持的 event 不同

          ?

          ?默認(rèn)情況下,arthas使用3658端口,則可以打開:http://localhost:3658/arthas-output/?查看到arthas-output目錄下面的profiler結(jié)果:

          profiler目錄

          選擇一項(xiàng)點(diǎn)擊

          profiler結(jié)果圖

          問題 8:怎樣直接從JVM內(nèi)查找某個(gè)類的實(shí)例?

          使用?vmtool?可以達(dá)成目的

          ?

          這個(gè)功能是 Arthas 3.5.1 新增的。可以參考官方文檔 https://arthas.aliyun.com/doc/vmtool.html#id1

          ?
          $?vmtool?--action?getInstances?--className?java.lang.String?--limit?10
          @String[][
          ????@String[com/taobao/arthas/core/shell/session/Session],
          ????@String[com.taobao.arthas.core.shell.session.Session],
          ????@String[com/taobao/arthas/core/shell/session/Session],
          ????@String[com/taobao/arthas/core/shell/session/Session],
          ????@String[com/taobao/arthas/core/shell/session/Session.class],
          ????@String[com/taobao/arthas/core/shell/session/Session.class],
          ????@String[com/taobao/arthas/core/shell/session/Session.class],
          ????@String[com/],
          ????@String[java/util/concurrent/ConcurrentHashMap$ValueIterator],
          ????@String[java/util/concurrent/locks/LockSupport],
          ]

          通過?--limit參數(shù),可以限制返回值數(shù)量,避免獲取超大數(shù)據(jù)時(shí)對(duì)JVM造成壓力。默認(rèn)值是10。

          如果想精確的定位到具體的類實(shí)例,可以通過指定 classloader name 或者 classloader hash,如下所示:

          vmtool?--action?getInstances?--classLoaderClass?org.springframework.boot.loader.LaunchedURLClassLoader?--className?org.springframework.context.ApplicationContext
          vmtool?--action?getInstances?-c?19469ea2?--className?org.springframework.context.ApplicationContext
          ?

          獲取 classloader hash 的方法請(qǐng)參考上面的問題 1

          ?

          vmtool 還有個(gè)不錯(cuò)的功能,可以「強(qiáng)制進(jìn)行GC」,這在某些生產(chǎn)環(huán)境內(nèi)存緊張的情況下有奇效。

          vmtool?--action?forceGc

          ??

          1.?圖文并茂,Spring Boot Starter 萬字詳解!還有誰(shuí)不會(huì)?

          2.?Redis 延時(shí)任務(wù),高手養(yǎng)成篇

          3.?Intellij IDEA 高效使用教程

          4.?Nginx+Redis 搭建高性能緩存利器

          最近面試BAT,整理一份面試資料Java面試BATJ通關(guān)手冊(cè),覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫(kù)、數(shù)據(jù)結(jié)構(gòu)等等。

          獲取方式:點(diǎn)“在看”,關(guān)注公眾號(hào)并回復(fù)?Java?領(lǐng)取,更多內(nèi)容陸續(xù)奉上。

          文章有幫助的話,在看,轉(zhuǎn)發(fā)吧。

          謝謝支持喲 (*^__^*)

          瀏覽 113
          點(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>
                  97免费在线视频 | 天天综合视频老女人 | 免费清高视频一黄色情 | 亚洲内射在线 | 91丨九色丨 黑色JK在线 91无码人妻精品1国产四虎 |