<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個問題5分鐘教你學(xué)會Arthas診斷工具

          共 17291字,需瀏覽 35分鐘

           ·

          2021-07-21 18:46

          你知道的越多,不知道的就越多,業(yè)余的像一棵小草!

          成功路上并不擁擠,因為堅持的人不多。

          編輯:業(yè)余草

          blog.csdn.net/Shockang

          推薦:https://www.xttblog.com/?p=5247

          前言

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

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

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

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

          坑爹啊

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

          管殺不管埋

          正文

          「下面是筆者結(jié)合多年使用 Arthas 的經(jīng)驗,針對這 8 個問題給出的詳細(xì)解決方案,如果有疑問歡迎評論區(qū)指出。」

          準(zhǔn)備

          先給出我的測試代碼

          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<People> 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<String> interests;
              }
          }

          以下是控制臺正常打印的結(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])]

          下載并運行 Arthas

          按照下圖中的步驟,選擇一個 Java 進程進行 attach。

          下載并運行Arthas

          訪問 WebConsole

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

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

          ?

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

          ?

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

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

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

          1. sc

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

          ?

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

          ?
          sc -d *ArthasDemo*

          sc-d命令
          1. classloader

          通過 classloader 查看 class 文件來自哪個 jar 包

          ?

          使用 cls 命令可以清空命令行,這個簡單的命令官方文檔居然找不到。。。

          ?
          ?

          注意 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?分支搞錯了?

          推薦使用 watchtt 命令,非常好用。

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

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

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

          ?

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

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

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

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

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

          ?

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

          ?
          tt-i命令
          ?

          圖中之所以可以打印興趣列表,是調(diào)用了其 toString 方法,如果沒有重寫 java.lang.Object 類的 toString 方法,只會看到 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<People> 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<String> 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<String> getInterests() {
                             return this.interests;
                         }

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

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

                         public void setInterests(List<String> interests) {
                             this.interests = interests;
                         }
                     }
                 }

          [arthas@3633]$

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

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

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

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

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

          這時我們就可以將新代碼編譯后的 class 文件熱替換正在運行的 ArthasDemo 的代碼。

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

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

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

          這個問題沒有完美的解決辦法

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

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

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

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

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

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

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

          ?

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

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

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

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

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

          使用 jvm 命令可以查看 JVM 的實時運行狀態(tài)。

          JVM 的實時運行狀態(tài)

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

          profiler 命令支持生成應(yīng)用熱點的火焰圖。本質(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目錄

          選擇一項點擊

          profiler結(jié)果圖

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

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

          ?

          這個功能是 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ù)時對JVM造成壓力。默認(rèn)值是10。

          如果想精確的定位到具體的類實例,可以通過指定 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 的方法請參考上面的問題 1

          ?

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

          vmtool --action forceGc

          瀏覽 98
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  亚洲AV无码久久精品色无码蜜桃 | 91 黄网站在线观看 | 免费看韩国毛片 | 欧美日韩高清在线观看 | 艹逼无码黄色的视频禁止 |