天天看點

中原銀行 Arthas 實踐之路一. 定制化功能改造二. 重點使用功能三. 應用實踐案例四.總結建議Arthas 征文活動火熱進行中

作者 | 于爽 中原銀行系統研發工程師,目前在技術平台室中間件小組從事分布式緩存、消息隊列等相關工作。

【Arthas 官方社群正在舉行征文活動,參加即有獎品拿哦~

點選投稿

Arthas 是一款 Java應用開源診斷工具,由于其強大的問題排查及診斷能力,自其開源以來廣受開發者的關注和使用,多次登頂 GitHub Trending,并得到國内多家技術媒體的推薦分享。

一. 定制化功能改造

Arthas 可以通過簡單的指令互動模式,接入運作的 JVM,快速定位和診斷線上程式運作問題。在不重新開機服務的情況下,實時、動态的修改相關 code,并實時生效。具體工作原理如下:

1. 連接配接JVM:通過attach機制,通過attach pid連接配接正在運作的JVM;
2. 檢視及修改JVM位元組碼:通過instrument技術對運作中的JVM附加或修改位元組碼來實作增強的邏輯。           

2018 年底,中原銀行開始投入人員對 Arthas 進行調研,在開源社群了解了主要功能,并通過閱讀 Arthas 工程大綱,明晰整體工程結構,整個執行過程如下:Arthas 底層調用 rt.jar 包的 ManagementFactory 擷取整個 jvm 内部資訊,通過指令內建與後端互動,執行,傳回結果,整個工程簡單清晰,容易上手。

2019 年初,中原銀行技術團隊開始使用推廣 Arthas 定位和診斷線上問題。

出于保護客戶敏感資訊的嚴格要求,同時切實保障生産環境業務系統的穩定運作,我們對 Arthas 的部分功能進行了定制化改造,對一些指令進行了隐藏:

1. watch:watch方法可以在沒有列印日志的情況下,看到方法的入參和傳回值,有可能暴露客戶的敏感資訊;
2. mc、redefine:mc組合rdefine可以對代碼進行熱更新,不能滿足我行生産運作管理規範要求。           

同時,出于使用需要,定制化開發了 gc 等指令:

1. gc:實時動态展示年輕代,年老代垃圾百分比,回收次數及耗時等情況。            

下一步,我行計劃在全部開發測試環境、部分生産環境推廣使用 Arthas 來進行問題排查與定位診斷。同時采用内部技術分享的形式向行内應用開發團隊普及推廣 Arthas 的使用。

二. 重點使用功能

除了日常問題排查使用到的方法外,Arthas 還有一些強大的功能,深受中原銀行技術團隊喜愛。

1.target-ip

# target-ip 為指定綁定的IP,如果不指定IP,Arthas隻listen 127.0.0.1,是以如果想從遠端連接配接,則可以使用 --target-ip參數指定listen的IP
java -jar arthas-boot.jar --target-ip IP           

綁定遠端通路IP後,可以在通過telnet或http的方式遠端連接配接 Arthas 進行問題排查。

web端通路位址:ip:8563

中原銀行 Arthas 實踐之路一. 定制化功能改造二. 重點使用功能三. 應用實踐案例四.總結建議Arthas 征文活動火熱進行中

/telnet通路:ip:3658

中原銀行 Arthas 實踐之路一. 定制化功能改造二. 重點使用功能三. 應用實踐案例四.總結建議Arthas 征文活動火熱進行中

當線上應用出現問題時,可以将問題機器隔離起來,通過Arthas在啟動時指定target-ip,多方技術人員可同時通過遠端連接配接進行問題排查。

2.trace

# 檢視方法内部調用路徑,并輸出方法路徑上的每個節點上耗時 
trace ClassName methodName           

使用 trace 指令可以一層一層追蹤耗時在哪裡 ,在進行性能調優的時候十分有效。

中原銀行 Arthas 實踐之路一. 定制化功能改造二. 重點使用功能三. 應用實踐案例四.總結建議Arthas 征文活動火熱進行中

3.ognl

ognl 是應用于 Java 中的一個開源的表達式語言,作用是對資料進行通路,它擁有類型轉換、通路對象方法、操作集合對象等功能,通過 ognl 可以完成一些列強大的操作。

  • 執行靜态方法
# 使用ognl調用靜态方法
ognl “@類名@方法名(參數)”           
  • 擷取靜态屬性
# 使用ognl擷取靜态屬性
ognl “@類名@屬性名”           
  • 示例:修改日志等級
# 查找目前類的classloader hashcode
sc -d 類名 | grep classLoaderHash
# 用OGNL擷取logger
ognl -c ***** '@類名@logger'
# 單獨設定該類的logger level
ognl -c ***** '@類名@logger.setLevel(@ch.qos.logback.classic.Level@DEBUG)'
#全局設定logger level
ognl -c ***** '@org.slf4j.LoggerFactory@getLogger("root").setLevel(@ch.qos.logback.classic.Level@DEBUG)'           

4.gc

gc 是我行定制化開發的功能,源自于 jstat -gcutil pid timeinterval 指令,其中 pid 可以從 Arthas 中擷取,timeinterval(機關為毫秒)表示 gc 每次時間間隔,預設為 1s。

# 檢視應用gc情況(timeinterval表示間隔時間,機關毫秒,預設為1S)
gc -i timeinterval -n 5           
中原銀行 Arthas 實踐之路一. 定制化功能改造二. 重點使用功能三. 應用實踐案例四.總結建議Arthas 征文活動火熱進行中

三. 應用實踐案例

下面記錄一些我行 Arthas 應用實踐案例(由于行内代碼保密性要求,下文所示案例均為場景複現所寫示例代碼)

案例一:系統 CPU 使用率高

問題描述:業務人員回報背景管理系統其中一個頁面響應時間很長,登入伺服器上發現 CPU 使用率較高,達到 80% 左右。

1. 啟動 Arthas,附加到對應的 java 程序

注意:Arthas 啟動時要使用與 Java 程序相同的啟動使用者。

# 啟動Arthas
   java -jar arthas-boot.jar
   [INFO] arthas-boot version: 3.2.0
   [INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.
   * [1]: 11360 org.gradle.launcher.daemon.bootstrap.GradleDaemon
     [2]: 12196 com.durian.ddp.Application
   # 選擇要附加的java程序編号
   2
   ...           

2. thread 指令檢視 CPU 使用率高的線程

啟動 Arthas,附加到對應的 java 程序,執行 thread -n 5 檢視 CPU 使用率最高的 5 個線程的堆棧。

# 檢視CPU使用率最高的5個線程
thread -n 5
at ***.TreeUtil.findMenuChildren(TreeUtil.java:94)
    at ***.TreeUtil.findMenuChildren(TreeUtil.java:92)
    at ***.TreeUtil.findMenuChildren(TreeUtil.java:92)
    at ***.TreeUtil.findMenuChildren(TreeUtil.java:92)
    at ***.TreeUtil.recursiveTree(TreeUtil.java:74)
    at ***.getOwnerDeparmentTree(DepartmentServiceImpl.java:550)
    ...
at ***.TreeUtil.findMenuChildren(TreeUtil.java:94)
    at ***.TreeUtil.findMenuChildren(TreeUtil.java:92)
    at ***.TreeUtil.findMenuChildren(TreeUtil.java:92)
    at ***.TreeUtil.findMenuChildren(TreeUtil.java:92)
    at ***.TreeUtil.recursiveTree(TreeUtil.java:74)
    at ***.getOwnerDeparmentTree(DepartmentServiceImpl.java:550)
    ...
...           

3. 通過 monitor 指令檢視方法的調用次數與耗時

通過 thread 指令已經定位到 CPU 主要消耗在

TreeUtil

findMenuChildren

方法上,通過 monitor 指令檢視方法的具體調用次數與耗時。

# 5s為一個統計周期,統計TreeUtil中findMenuChildren方法的耗時
monitor -c 5 ***.TreeUtil findMenuChildren           
中原銀行 Arthas 實踐之路一. 定制化功能改造二. 重點使用功能三. 應用實踐案例四.總結建議Arthas 征文活動火熱進行中

通過 monitor 指令可以明确該方法單次調用平均耗時為 17 ~ 20ms,但是調用次數多,是以整體上頁面響應慢。

4. 通過 jad 指令反編譯 TreeUtil 類,檢視源碼

[arthas@12196]$ jad com.durian.ddp.utils.TreeUtil
ClassLoader:
+-sun.misc.Launcher$AppClassLoader@18b4aac2
  +-sun.misc.Launcher$ExtClassLoader@244038d0
Location:
/*
 * Decompiled with CFR.
 *
 * Could not load the following classes:
 *  ***.ResourceTreeVo
 */
...
public class TreeUtil {
    public static ResourceTreeVo findMenuChildren(ResourceTreeVo resourceTreeVo, List<ResourceTreeVo> treeNodes) {
        for (ResourceTreeVo resource : treeNodes) {
            if (!resourceTreeVo.getResourceId().equals(resource.getResourceParentId())) continue;
            if (resourceTreeVo.getChildResourceVo() == null) {
                resourceTreeVo.setChildResourceVo(new ArrayList());
            }
            resourceTreeVo.getChildResourceVo().add(TreeUtil.findMenuChildren(resource, treeNodes));
        }
        return resourceTreeVo;
    }
    public static List<ResourceTreeVo> recursiveTree(List<ResourceTreeVo> list) {
        ArrayList<ResourceTreeVo> trees = new ArrayList<ResourceTreeVo>();
        for (ResourceTreeVo treeNode : list) {
            if (!StringUtils.isEmpty(treeNode.getResourceParentId())) continue;
            trees.add(TreeUtil.findMenuChildren(treeNode, list));
        }
        return trees;
    }
}           

通過 jad 指令檢視源碼可以發現,此處的業務邏輯大緻是通過

ResourceTreeVo

對象的

resourceParentId

字段把一個清單建構一個樹。在

findMenuChildren

方法中存在遞歸調用,而且每一次調用都需要周遊整個

ResourceTreeVo

清單來查找子節點,時間複雜度為 O(n)。是以在

ResourceTreeVo

清單元素比較多的時候,會很耗時。

5. 解決問題

定位到問題就友善解決了,可以通過提前基于 list 建構一個

parentId->List<ResourceTreeVo>

的 map,每個節點查找子節點清單的時候可以從 map 中擷取。這樣整個建構樹的時間算法為 O(n)。

案例二:應用線程連接配接數異常

問題描述:伺服器句柄數耗盡,檢視發現某個應用占用句柄數較多。

中原銀行 Arthas 實踐之路一. 定制化功能改造二. 重點使用功能三. 應用實踐案例四.總結建議Arthas 征文活動火熱進行中

1. thread 指令檢視線程資訊

啟動 Arthas,附加到對應的 java 程序,執行 thread 檢視線程情況。

# 檢視線程情況
thread            
中原銀行 Arthas 實踐之路一. 定制化功能改造二. 重點使用功能三. 應用實踐案例四.總結建議Arthas 征文活動火熱進行中
中原銀行 Arthas 實踐之路一. 定制化功能改造二. 重點使用功能三. 應用實踐案例四.總結建議Arthas 征文活動火熱進行中

看到有大量的

MasterListener-mymaster-*

線程處于連接配接狀态,一直沒有釋放。

# 選擇其中一個線程檢視堆棧資訊
thread id             
中原銀行 Arthas 實踐之路一. 定制化功能改造二. 重點使用功能三. 應用實踐案例四.總結建議Arthas 征文活動火熱進行中

發現這些線程是由

redis.clients.JedisSentinelPool$MasterListener

産生的,那麼接下來就來檢視一下

JedisSentinelPool$MasterListener

的調用情況。

2. stack 指令檢視堆棧資訊

stack redis.clients.jedis.JedisSentinelPool$MasterListener           

觸發一次應用請求,列印出如下堆棧資訊:

中原銀行 Arthas 實踐之路一. 定制化功能改造二. 重點使用功能三. 應用實踐案例四.總結建議Arthas 征文活動火熱進行中

通過調用鍊定位到

RedisUtil

類,發現每次請求否會觸發

RedisUtil.getJedis

方法調用

JedisSentinelPool$MasterListener

,那麼下一步我們反編譯一下

REedisUtil

類。

3. jad 指令反編譯檢視代碼

# 反編譯RedisUtil類
jad cn.com.zybank.testredis.starter.RedisUtil           
中原銀行 Arthas 實踐之路一. 定制化功能改造二. 重點使用功能三. 應用實踐案例四.總結建議Arthas 征文活動火熱進行中

檢視

getJedis

方法,發現

getJedis

每調用一次都會建立一個

JedisSentinelPool

中原銀行 Arthas 實踐之路一. 定制化功能改造二. 重點使用功能三. 應用實踐案例四.總結建議Arthas 征文活動火熱進行中

通過分析發現,每次使用 redis 時,都會調用

getJedis

方法建立一個新的

JedisSentinelPool

,進而啟動一個

MasterListener-mymaster-*

線程,由于該線程會一直保持監聽,不會自動釋放,故随着應用請求的增加線程數一直增加進而導緻連接配接數占滿。

4. 解決問題

針對該問題,隻需建立一個全局的

JedisSentinelPool

,每次擷取 redis 連接配接時都從該連接配接池擷取即可,這裡不再對代碼進行展示。

四.總結建議

我行在使用 Arthas 以前,線上問題排查往往需要查網絡、jps、jstack、jmap、jhat、jstat、hprof 等一系列操作,費時費力。目前,大多數的常見問題都可以使用 Arthas 輕松定位,迅速解決。

一鍵安裝并啟動 Arthas

  • 方式一:通過 Cloud Toolkit 實作 Arthas 一鍵遠端診斷

Cloud Toolkit 是阿裡雲釋出的免費本地 IDE 插件,幫助開發者更高效地開發、測試、診斷并部署應用。通過插件,可以将本地應用一鍵部署到任意伺服器,甚至雲端(ECS、EDAS、ACK、ACR 和 小程式雲等);并且還内置了 Arthas 診斷、Dubbo工具、Terminal 終端、檔案上傳、函數計算 和 MySQL 執行器等工具。不僅僅有 IntelliJ IDEA 主流版本,還有 Eclipse、Pycharm、Maven 等其他版本。

推薦使用 IDEA 插件下載下傳 Cloud Toolkit 來使用 Arthas:

http://t.tb.cn/2A5CbHWveOXzI7sFakaCw8
  • 方式二:直接下載下傳

位址:

https://github.com/alibaba/arthas

随着我行全面深化使用 Arthas,也發現了一些有待改進提升的功能,希望進一步優化完善。

  • 在進行 trace 的時候,隻要調用鍊中有異步,堆棧就會斷掉,無法 trace 到子線程内部,隻能手動逐層跟進 trace,效率較低。
  • 希望 tt 指令能夠添加異步開關,如果開關開啟, 那麼 COST 即可顯示異步得到結果的耗時。

截至目前,Arthas GitHub Star 已經突破 2.4 萬了,希望 Arthas 能夠獲得更多全球開發者的關注和喜愛,也期待更多像 Arthas 一樣的國内優質項目能夠開源。

Arthas 征文活動火熱進行中

Arthas 官方正在舉行征文活動,如果你有:

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

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

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