日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

Arthas : 具体问题分析小册子

發(fā)布時(shí)間:2023/12/31 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Arthas : 具体问题分析小册子 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

目錄

前言

正文

準(zhǔn)備

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

下載并運(yùn)行 Arthas

訪問(wèn) WebConsole

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

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

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

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

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

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

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

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


前言

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

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

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

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

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

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

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

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

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

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

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

    ?

    正文

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

    準(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)用方法的過(guò)程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;/***?電話(huà)*/String?telephone;/***?興趣列表*/List<String>?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

    訪問(wèn) WebConsole

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

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

    ?

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

    ?

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

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

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

  • sc

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

    ?

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

    ? sc?-d?*ArthasDemo*

    sc-d命令

  • classloader

  • 通過(guò)?classloader?查看 class 文件來(lái)自哪個(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 文件來(lái)自 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

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

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

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

  • 使用?watch?命令查看方法調(diào)用情況。我們要查看 ArthasDemo 這個(gè)類(lèi)里面的 convert 方法調(diào)用情況。

  • watch命令

    watch?com.shockang.study.ArthasDemo?convert?"{params,target,returnObj}"?-f?-x?4

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

    ?

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

    ?
  • 使用?tt?命令來(lái)觀測(cè)方法調(diào)用情況,tt?命令可以查看「多次調(diào)用」并選擇其中一個(gè)進(jìn)行觀測(cè),但是如果輸出結(jié)果是多層嵌套就沒(méi)辦法看了,而?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í)間片的信息而言,你可以通過(guò) -i 參數(shù)后邊跟著對(duì)應(yīng)的 INDEX 編號(hào)查看到他的詳細(xì)信息

    ?

    tt-i命令

    ?

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

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

  • 通過(guò)?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]$

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

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

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

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

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

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

    redefine命令

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

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

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

    這個(gè)問(wèn)題沒(méi)有完美的解決辦法

    參考一下問(wèn)題 2 和問(wèn)題 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秒

    ?

    問(wèn)題 5:是否有一個(gè)全局視角來(lái)查看系統(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ù), 線(xiàn)程池信息等等。

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

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

    問(wèn)題 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)

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

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

    ?

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

    ?

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

    profiler目錄

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

    profiler結(jié)果圖

    問(wèn)題 8:怎樣直接從JVM內(nèi)查找某個(gè)類(lèi)的實(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], ]

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

    如果想精確的定位到具體的類(lèi)實(shí)例,可以通過(guò)指定 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)參考上面的問(wèn)題 1

    ?

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

    vmtool?--action?forceGc

    總結(jié)

    以上是生活随笔為你收集整理的Arthas : 具体问题分析小册子的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。