天天看點

阿裡開源的那個牛X的問題排查工具——Arthas,推出IDEA插件了!Arthas IDEA plugin 實踐總結

作者 | 汪小哥

Arthas 對于很多 Java 開發者來說,已經不可分割了,在我們日常開發、線上問題排查中扮演了非常重要的角色。作為小開發的我,日常需要排查線上營運同學提的各種 bug、各種線上問題診斷、日常運維、線上問題優化等等。

在剛來公司時,我是比較恐懼運維任務的,代碼不熟悉、各種問題比較多...幾乎崩潰的狀态,運維的一周基本上沒有幹活,完全是全身心投入到運維的任務中,排查問題效率低下。

由于深刻體驗到了這種奔潰,我一直想改變這種狀态,直到 Arthas 的開源,讓我在這種崩潰的狀态中減輕了不少負擔,同時也讓我成為了同僚們咨詢 Arthas 排查問題的小幫手~~ 雖然使用 Arthas 特别友善,但在此過程中也遇到一些問題,作為問題咨詢小幫手也感到有點不友善,是以才造就了 Arthas idea 插件的誕生。

阿裡開源的那個牛X的問題排查工具——Arthas,推出IDEA插件了!Arthas IDEA plugin 實踐總結

目前 Arthas 官方的工具還不夠簡單,需要記住一些指令,特别是一些擴充性特别強的進階文法,比如 ognl 擷取 spring context 為所欲為,watch、trace 不夠簡單,需要構造一些指令工具的資訊,是以隻需要一個能夠簡單處理字元串資訊的插件即可使用。

當在處理線上問題的時候需要最快速、最便捷的指令,是以 Idea Arthas plugin 插件還是有存在的意義和價值的。---這個是最初編寫這個插件的最核心的理由。

Arthas IDEA plugin 實踐

Arthas 的功能點非常的多(詳見下方大圖),這裡就不一一的講解了,可以參考使用文檔 ,不過最近一直在更新,使用文檔中的指令名稱可能有變化。

阿裡開源的那個牛X的問題排查工具——Arthas,推出IDEA插件了!Arthas IDEA plugin 實踐總結

插件安裝

下載下傳 arthas idea 插件:

https://plugins.jetbrains.com/plugin/13581-arthas-idea
  • Mac: 

    Preferences

     -> 

    Plugins

  • Windows:

    Settings

    Plugins

Install Plugin form Disk... 導入插件

阿裡開源的那個牛X的問題排查工具——Arthas,推出IDEA插件了!Arthas IDEA plugin 實踐總結

安裝之後重新開機 IDEA 就可以愉快的使用啦!

擷取 static 變量

首先要擷取 classloader 的 hash 值,然後擷取指令,這個是一個互動流程需要連貫性,後續隻要是 static 的通過 static spring context 的都需要有這個互動的流程,連貫的,都在同一個界面進行操作.粘貼執行,然後擷取結果即可。

這裡的 classloader 的 hash 值緩存起來的
阿裡開源的那個牛X的問題排查工具——Arthas,推出IDEA插件了!Arthas IDEA plugin 實踐總結
阿裡開源的那個牛X的問題排查工具——Arthas,推出IDEA插件了!Arthas IDEA plugin 實踐總結

最後合并的腳本如下。

ognl  -x  3 '@com.wangji92.arthas.plugin.demo.controller.StaticTest@INVOKE_STATIC_NAME' -c 316bc132           

反射設定 static field

通過反射進行設定 static field ,參考:

https://github.com/WangJi92/arthas-idea-plugin/issues/1
阿裡開源的那個牛X的問題排查工具——Arthas,推出IDEA插件了!Arthas IDEA plugin 實踐總結

填寫你想要修改的值、預設根據類型設定預設值 Str->"" Long -> 0L 等等。

阿裡開源的那個牛X的問題排查工具——Arthas,推出IDEA插件了!Arthas IDEA plugin 實踐總結
ognl -x 3  '#[email protected]@class.getDeclaredField("INVOKE_STATIC_FINAL"),#modifiers=#field.getClass().getDeclaredField("modifiers"),#modifiers.setAccessible(true),#modifiers.setInt(#field,#field.getModifiers() & [email protected]@FINAL),#field.setAccessible(true),#field.set(null,"設定的值")' -c 316bc132           

Spring Context Invoke

通過 spring context 進行調用 bean 的方法、字段的内容。

Static Spring Context Invoke Method Field

首頁要設定一下 static spring context 的路徑。

阿裡開源的那個牛X的問題排查工具——Arthas,推出IDEA插件了!Arthas IDEA plugin 實踐總結
阿裡開源的那個牛X的問題排查工具——Arthas,推出IDEA插件了!Arthas IDEA plugin 實踐總結

由于都是通過 ognl 調用 static 的 spring context 都需要 classloader,這個就是配置的 spring conetxt 的位址資訊:

@com.wangji92.arthas.plugin.demo.common.ApplicationContextProvider@context 參考 demo 就需要配置這個位址。

ognl -x 3 '#springContext=@com.wangji92.arthas.plugin.demo.common.ApplicationContextProvider@context,#springContext.getBean("commonController").getRandomInteger()' -c 316bc132           

Watch Spring Context Invoke Method Field

watch 這個是支援在 spring mvc 場景,通過 watch 間接的擷取 spring context,需要出發一次接口的調用,可以參考 :

https://github.com/WangJi92/arthas-idea-plugin/issues/5
阿裡開源的那個牛X的問題排查工具——Arthas,推出IDEA插件了!Arthas IDEA plugin 實踐總結
watch -x 3 -n 1  org.springframework.web.servlet.DispatcherServlet doDispatch '@org.springframework.web.context.support.WebApplicationContextUtils@getWebApplicationContext(params[0].getServletContext()).getBean("commonController").getRandomInteger()'           

TimeTunnel Spring Context Invoke Method Field

這個是參考了橫雲斷嶺的 arthas 通過 tt 擷取 spring context 為所欲為 ,可以參考這個文檔:

https://github.com/WangJi92/arthas-idea-plugin/issues/4

這裡做了些什麼?将整個連貫了起來,不需要記住參數資訊,然後對于調用的參數進行簡單的預設封裝,複雜的參數場景不支援,需要手動拼接。

阿裡開源的那個牛X的問題排查工具——Arthas,推出IDEA插件了!Arthas IDEA plugin 實踐總結

記錄擷取 spring context

tt -t org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter invokeHandlerMethod           

然後根據這個 target 擷取 spring context 調用方法

tt -w 'target.getApplicationContext().getBean("commonController").getRandomInteger()' -x 3 -i 1000           

擷取某個 spring 環境變量

擷取 spring 環境變量這裡依托,static spring context ,當然這個 watch 、和 tt 擷取 spring context 的場景也是支援的。線上上環境、測試環境程式多複雜,你怎麼知道環境中的變量一定是你配置的?在 nacos 等等配置中心的場景,估計手速慢了一點點,可能就沒有上去,這個時候就有這種需求擷取目前的環境變量。選中變量,然後右鍵執行指令。由于使用靜态的 static spring context 依然需要 classloader 的值。這裡已經基本上是 arthas 的上層應用啦。

阿裡開源的那個牛X的問題排查工具——Arthas,推出IDEA插件了!Arthas IDEA plugin 實踐總結
阿裡開源的那個牛X的問題排查工具——Arthas,推出IDEA插件了!Arthas IDEA plugin 實踐總結
ognl -x 3 '#springContext=@com.wangji92.arthas.plugin.demo.common.ApplicationContextProvider@context,#springContext.getEnvironment().getProperty("custom.name")' -c 316bc132           

擷取全部的 spring 環境變量

比較優先級,最前面的一定優先級最高,你一定被 spring 的各種優先級順序搞暈了,那麼怎麼辦呢?arthas idea plugin 支援擷取目前的全部的環境變量,依次列印出來,這樣就可以了解優先級,特别是接入了 nacos、diamond 等遠端的配置中心,實作不一樣肯定更暈了。

參考文檔:

https://blog.csdn.net/xunjiushi9717/article/details/94050139
阿裡開源的那個牛X的問題排查工具——Arthas,推出IDEA插件了!Arthas IDEA plugin 實踐總結
阿裡開源的那個牛X的問題排查工具——Arthas,推出IDEA插件了!Arthas IDEA plugin 實踐總結
ognl -x 3 '#springContext=@com.wangji92.arthas.plugin.demo.common.ApplicationContextProvider@context,#allProperties={},#standardServletEnvironment=#propertySourceIterator=#springContext.getEnvironment(),#propertySourceIterator=#standardServletEnvironment.getPropertySources().iterator(),#propertySourceIterator.{#key=#this.getName(),#allProperties.add("                "),#allProperties.add("------------------------- name:"+#key),#this.getSource() instanceof java.util.Map ?#this.getSource().entrySet().iterator.{#key=#this.key,#allProperties.add(#key+"="+#standardServletEnvironment.getProperty(#key))}:#{}},#allProperties' -c 316bc132           

TimeTunnel Tt

方法執行資料的時空隧道,記錄下指定方法每次調用的入參和傳回資訊,并能對這些不同的時間下調用進行觀測(可以重新觸發,周期觸發,唯一缺點對于 ThreadLocal 資訊丢失[隐含參數]、引用對象資料變更無效),這個友善二次觸發,特别是自己調試不友善的情況下記錄下來,二次觸發、周期觸發,不過自從段嶺大神 tt 為所欲為之後都被帶偏了。這裡 arthas 插件做了一些什麼?增加了二次觸發的一些常用的指令,不讓使用者愁于記憶,整個過程更加的具有連貫性。

阿裡開源的那個牛X的問題排查工具——Arthas,推出IDEA插件了!Arthas IDEA plugin 實踐總結
阿裡開源的那個牛X的問題排查工具——Arthas,推出IDEA插件了!Arthas IDEA plugin 實踐總結

stack 堆棧

擷取方法從哪裡執行的調用棧(用途:源碼學習調用堆棧,了解調用流程) 這個是非常好用的功能,對于喜歡樂于排查問題的小夥伴真是福音,arthas idea 插件隻是修改的指令的內建,之前也處理自己編碼過程中的問題,源碼、問題排查技巧-Java Debug and Arthas:

https://blog.csdn.net/u012881904/article/details/104591529
stack com.wangji92.arthas.plugin.demo.controller.CommonController getRandomInteger -n 5           

Decompile Class Jad

反編譯方法、類的源碼, 有時候需要檢視送出的代碼是否上線呢?這個功能就非常的友好。

參考文檔:[

https://github.com/WangJi92/arth!

as-idea-plugin/issues/2](

https://github.com/WangJi92/arthas-idea-plugin/issues/2)
阿裡開源的那個牛X的問題排查工具——Arthas,推出IDEA插件了!Arthas IDEA plugin 實踐總結
jad --source-only com.wangji92.arthas.plugin.demo.controller.CommonController getRandomInteger           

watch、trace

增加了預設參數、預設展開的層級限制次數,使用者不用知道這些核心的參數,簡單的使用就好了,要使用更加的進階的自己help 一下就知道了。

watch com.wangji92.arthas.plugin.demo.controller.CommonController getRandomInteger '{params,returnObj,throwExp}' -n 5 -x 3
trace com.wangji92.arthas.plugin.demo.controller.CommonController getRandomInteger -n 5           

trace -E(層級的列印 trace)

trace -E 自己構造起來非常的麻煩,通過界面操作簡化了一下,需要觀察多個類、多個方法的場景。選擇你需要的場景繼續添加即可。

阿裡開源的那個牛X的問題排查工具——Arthas,推出IDEA插件了!Arthas IDEA plugin 實踐總結
trace -E com.wangji92.arthas.plugin.demo.controller.CommonController|com.wangji92.arthas.plugin.demo.service.ArthasTestService traceE|doTraceE -n 5           

Heap Dump

列印堆棧,有點類似 jmap -dump:format=b,file=/temp/dump.hprof pid 下載下傳下來使用 MAT 分析即可。

heapdump  /tmp/dump.hprof 列印堆棧資訊            
阿裡開源的那個牛X的問題排查工具——Arthas,推出IDEA插件了!Arthas IDEA plugin 實踐總結

特殊用法連結

這個必須要說一下,這個特殊用法的連結線上上自己束手無措的時候可以檢視一下,非常有用。

阿裡開源的那個牛X的問題排查工具——Arthas,推出IDEA插件了!Arthas IDEA plugin 實踐總結
阿裡開源的那個牛X的問題排查工具——Arthas,推出IDEA插件了!Arthas IDEA plugin 實踐總結

對于通過 spring context 調用方法說明

通過 spring context 調用複雜的方法其實是不支援的,由于這個操作起來不友善,還是必須手工處理一下。

比如這裡的 Map names 的處理方式可以借鑒一下子。

更多可以參考 demo:

https://github.com/WangJi92/arthas-plugin-demo
/**
     * 複雜參數調用 場景
     * static spring context
     * ognl -x 3 '#user=new com.wangji92.arthas.plugin.demo.controller.User(),#user.setName("wangji"),#user.setAge(27L),#springContext=@com.wangji92.arthas.plugin.demo.common.ApplicationContextProvider@context,#springContext.getBean("commonController").complexParameterCall(#{"wangji":#user})' -c e374b99
     *
     * watch get spring context 備注 需要調用一次方法
     * watch -x 3 -n 1  org.springframework.web.servlet.DispatcherServlet doDispatch '#user=new com.wangji92.arthas.plugin.demo.controller.User(),#user.setName("wangji"),#user.setAge(27L),@org.springframework.web.context.support.WebApplicationContextUtils@getWebApplicationContext(params[0].getServletContext()).getBean("commonController").complexParameterCall(#{"wangji":#user})'
     *
     * tt get spring context ,only first get time index ok
     * tt -w '#user=new com.wangji92.arthas.plugin.demo.controller.User(),#user.setName("wangji"),#user.setAge(27L),target.getApplicationContext().getBean("commonController").complexParameterCall(#{"wangji":#user})' -x 3 -i 1000
     * @return
     */
    @RequestMapping("complexParameterCall")
    @ResponseBody
    public String complexParameterCall(@RequestBody  Map<String, User> names) {
        if (names == null) {
            return "EMPTY";
        }
        return names.toString();
    }           

總結

本文簡單介紹了 Arthas IDEA 插件的安裝與使用技巧,該插件解放了大家對于 Arthas 使用的一些記憶、機械性的重複工作,歡迎大家試用!

Arthas 官方舉行了征文活動,于 3 月 26 日—— 4 月 26 日舉辦,如果你有:

  • 使用 Arthas 排查過的問題
  • 對 Arthas 進行源碼解讀
  • 對 Arthas 提出建議
  • 不限,其它與 Arthas 有關的内容

 歡迎參加征文活動,還有獎品拿哦~

點選了解詳情

阿裡巴巴雲原生 關注微服務、Serverless、容器、Service Mesh 等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,做最懂雲原生開發者的技術圈。”