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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

中原银行 Arthas 实践之路

發布時間:2025/3/20 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 中原银行 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

/telnet訪問:ip:3658

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

2.trace

# 查看方法內部調用路徑,并輸出方法路徑上的每個節點上耗時 trace ClassName methodName

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

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 應用實踐案例(由于行內代碼保密性要求,下文所示案例均為場景復現所寫示例代碼)

案例一:系統 CPU 使用率高

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

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

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

# 啟動Arthasjava -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

通過 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)。

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

問題描述:服務器句柄數耗盡,查看發現某個應用占用句柄數較多。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-uZTAuL61-1591956702223)(https://ucc.alicdn.com/pic/developer-ecology/a5008a2ab76348bab3b46e0b7db57b68.png)]

1. thread 命令查看線程信息

啟動 Arthas,附加到對應的 java 進程,執行 thread 查看線程情況。

# 查看線程情況 thread

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-C45nVnO5-1591956702224)(https://ucc.alicdn.com/pic/developer-ecology/afcbbef4ee3540288a3bada9e65c4014.png)]

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-NagqPgEH-1591956702225)(https://ucc.alicdn.com/pic/developer-ecology/6d542d61e65c41f29155fbbb053451b8.png)]

看到有大量的 MasterListener-mymaster-* 線程處于連接狀態,一直沒有釋放。

# 選擇其中一個線程查看堆棧信息 thread id

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-QptvPcm8-1591956702227)(https://ucc.alicdn.com/pic/developer-ecology/f87a4d97295646678d9dfdbfe933139b.png)]

發現這些線程是由 redis.clients.JedisSentinelPool$MasterListener 產生的,那么接下來就來查看一下 JedisSentinelPool$MasterListener 的調用情況。

2. stack 命令查看堆棧信息

stack redis.clients.jedis.JedisSentinelPool$MasterListener

觸發一次應用請求,打印出如下堆棧信息:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-y5K9q3rl-1591956702228)(https://ucc.alicdn.com/pic/developer-ecology/b684fd9508fb4b2d9c8ad0ba2db504b1.png)]

通過調用鏈定位到 RedisUtil 類,發現每次請求否會觸發 RedisUtil.getJedis 方法調用 JedisSentinelPool$MasterListener,那么下一步我們反編譯一下 REedisUtil 類。

3. jad 命令反編譯查看代碼

# 反編譯RedisUtil類 jad cn.com.zybank.testredis.starter.RedisUtil

查看 getJedis 方法,發現 getJedis 每調用一次都會新建一個 JedisSentinelPool 。

通過分析發現,每次使用 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 等技術領域、聚焦云原生流行技術趨勢、云原生大規模的落地實踐,做最懂云原生開發者的公眾號。”

總結

以上是生活随笔為你收集整理的中原银行 Arthas 实践之路的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。