最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用Arthas定位問題及分析

 更新時間:2025年01月03日 08:56:46   作者:萊特昂  
本文通過使用Arthas工具對一個bug進行分析,發(fā)現該bug的原因是不同類型的動態(tài)代理(JDK和CGlib)實現機制的不同導致的

功能概述

首先,Arthas的常用功能大概有以下幾個:

解決依賴沖突

  • sc命令:模糊查看當前 JVM 中是否加載了包含關鍵字的類,以及獲取其完全名稱。 sc -d 關鍵字注意使用 sc -d 命令,獲取
  • classLoaderHash命令:通過 classloader 查看 class 文件來自哪個 jar 包 注意 classloader -c后面的值填上面獲取到的 classLoaderHash值 查看線上運行的代碼源碼,是否是預期的(確認代碼是否提交,分支是否正確)
  • jad --source-only:可以查看源代碼。
  • watch命令:查看方法調用情況。后面跟上完全類名和方法名,以及一個 OGNL的表達式,-f 表示不論正常返回還是異常返回都進行觀察,-x 表示輸出結果的屬性遍歷深度,默認為 1,建議無腦寫 4就行,最大的遍歷深度,再大就不支持了
  • tt命令:觀測方法調用情況,tt命令可以查看「多次調用」并選擇其中一個進行觀測,但是如果輸出結果是多層嵌套就沒辦法看了,而 watch 可以查看「多層嵌套」的結果。

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

  • 熱啟動(類似JRebel)

redefine 命令:「熱替換」線上的代碼,注意應用重啟之后會失效,這在某些緊急情況下會有奇效。比如說我們修改一下方法體里面的代碼,加了一行日志打印

  • 看程序運行時的整體情況

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

  • 查看程序運行時的jvm狀態(tài)

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

  • 定位應用運行中的熱點分析系統(tǒng)瓶頸

profiler 命令:支持生成應用熱點的火焰圖。本質上是通過不斷的采樣,然后把收集到的采樣結果生成火焰圖。

應用實例

背景

項目使用了MumbleSDK 2.x,rmb請求先到一個Dispatcher類,然后Dispatcher根據請求參數里的bizServiceId把請求分發(fā)到不同的子服務接口. 各個子服務接口上有個@MumbleMessageService標注著自己對應的bizServiceId.

上個月有個一次性的補數需求,圖方便我就直接在子服務的類里用@Async寫了個異步方法,分發(fā)服務Dispatcher就識別不到@MumbleMessageService注解找不到子服務了. 根據組內其他小伙伴的經驗,是因為這個類被spring代理了導致的. 后來把異步方法抽到單獨的類實現,服務就正常了.

但這個bug在測試環(huán)境沒有復現過,如果是代理問題,那么在什么環(huán)境都應該復現才對,這篇文章就是尋找測試環(huán)境沒復現的原因,以及從源碼層面上分析為什么@Async會導致找不到子服務的注解.

本地調試

開發(fā)環(huán)境運行后bug復現了,看了Dispatcher分發(fā)服務的源碼,原理是系統(tǒng)啟動時掃描所有繼承了MumbleBaseService的類,然后遍歷實現類以及父類里的方法是否帶有@MumbleMessageService,如果有就放在緩存里,請求過來時就從緩存里取出對應的服務.

在掃描結束的位置加了斷點,可以看到出問題的那個類由于有個方法用了@Async,類名帶有$Proxy,是個JDK動態(tài)代理類. 而JDK動態(tài)代理類和它的父類java.lang.reflect.Proxy 方法上都沒有@MumbleMessageService,所以不會被Dispatcher放進緩存,子服務自然識別不到了.

那么測試環(huán)境的類是什么樣的呢?為什么注解能識別到呢? 使用神器Arthas試試.

使用Arthas

1. 首先使用sc命令查看jvm里加載的類信息

發(fā)現有個類名帶有 $Enhancer By Spring CG LIB EnhancerBySpringCGLIB EnhancerBySpringCGLIB,是cglib代理類,而本地調試時類名帶有$Proxy,是JDK代理類,這個差異很可能就是造成測試環(huán)境bug沒復現的原因. 而且有好多個在開發(fā)環(huán)境正常的類測試環(huán)境也變成代理類了. 應該是有個地方統(tǒng)一給這些類做了增強. 于是現在問題就變成了 哪里使用了cglib代理了這些類,而且只在測試環(huán)境才使用了呢?

我自己項目里的代碼里是沒這樣用的,可能是在某個引用的包里. 繼續(xù)挖.

2. 這次使用trace命令查看方法的調用鏈,想看看調用鏈里有沒有發(fā)現

輸入命令后,發(fā)送一筆請求,發(fā)現只有各個節(jié)點的耗時時長,沒有別的信息了. 官方文檔這個命令的說明是方法內部調用路徑,并輸出方法路徑上的每個節(jié)點上耗時,看來只能看到方法內部的調用鏈,方法外的看不到,而我要找的是哪里增強了這個方法.

3. 接下去嘗試使用stack命令查詢方法被調用的調用路徑

下圖是發(fā)送請求后stack命令打印出來的東西,出現了一個mumbleSDK里的類,名字看起來就是使用了AOP切面

找到這個類源碼,就是它了! MumbleSDK里的dao,rmb調用耗時監(jiān)控組件,給項目里service目錄下的類都做了cglib代理,而且只有測試環(huán)境滿足了@Conditional里的條件所以開啟了.

讓我們驗證下,在項目的配置文件里加上 mumble.monitor.web.enabled=false 關閉這個監(jiān)控服務. 部署到測試環(huán)境后bug終于重現了. 再次使用sc查看,之前的cglib代理類已經變成JDK代理了

4. 用jad命令反編譯兩種不同的代理類

下圖是cglib的,可以看到繼承的父類是原來的類. 再復習下MumbleSDK Dispatcher識別服務的原理: 遍歷實現類以及父類的方法掃描@MumbleMessageService注解. 所以可以識別到方法上的@MumbleMessageService并把子服務加進緩存. 這就是一開始測試環(huán)境能識別到子服務的原因.

下圖是jdk代理類,父類是Proxy,方法上沒有@MumbleMessageService. 也就會出現找不到子服務的問題了.

所以這個bug的根本原因是不同類型的動態(tài)代理的實現差異導致的,而不是一開始認為的單純是因為被代理了.

下圖是@EnableAsync里的代碼,默認是jdk代理.

回到本地開發(fā)環(huán)境,把@EnableAsync改成 @EnableAsync(proxyTargetClass = true),強制使用cglib代理. 重啟服務,開發(fā)環(huán)境的服務也正常了.

但是,為了能亂放@Async而去改spring的默認代理配置是不合理的,還是要把@Async方法獨立出去.

Arthas Idea插件

命令或類名太長記不得可以安裝使用Aethas的idea插件,如下圖,在方法上右鍵選中相應的命令,就可以把命令復制到剪貼板,直接去終端粘貼使用就行了. 比如下圖粘貼的結果是

stack cn.webank.pmbank.cp.ocr.service.impl.OcrCorePojoService DoCommonOcr -n 5

總結

以前只了解過兩種動態(tài)代理的實現機制及區(qū)別,沒感受過這種區(qū)別對系統(tǒng)運行造成的影響. 就這個bug來說,是代理類的父類不同造成的.以后如果遇到這類問題也多了個debug思路.

Arthas真香. 以前debug時用的笨方法都可以用它代替. 比如定位接口耗時長問題,不用在代碼里一段段打印耗時日志再重新部署了,一行trace命令就可以打印出各個鏈路的耗時; 比如不確定部署的代碼是不是剛才更新的,可以使用jad反編譯查看變更的類.

帶有@Async @Schedule @Transation 等注解的方法最好分類放到單獨的類里,比如專門的異步任務類,定時任務類等.不僅能避免代理方面的問題,也能使代碼結構更清晰整潔.

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • Mybatis-Plus中updateById方法不能更新空值問題解決

    Mybatis-Plus中updateById方法不能更新空值問題解決

    本文主要介紹了Mybatis-Plus中updateById方法不能更新空值問題解決,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-08-08
  • 使用CXF和Jersey框架來進行Java的WebService編程

    使用CXF和Jersey框架來進行Java的WebService編程

    這篇文章主要介紹了使用CXF和Jersey框架來進行Java的WebService編程,Web service是一個平臺獨立的低耦合的自包含的基于可編程的web的應用程序,需要的朋友可以參考下
    2015-12-12
  • spring?boot?動態(tài)生成接口實現類的場景分析

    spring?boot?動態(tài)生成接口實現類的場景分析

    本文不具體介紹動態(tài)代理,主要看一下它在springboot項目中的實際應用,下面我們模仿feign來實現一個調用三方接口的?httpclient,感謝的朋友跟隨小編一起看看吧
    2021-11-11
  • Win10?IDEA如何連接虛擬機中的Hadoop(HDFS)

    Win10?IDEA如何連接虛擬機中的Hadoop(HDFS)

    在虛擬機上配置Hadoop并修改core-site.xml文件,設置IP為局域網地址,IDEA中創(chuàng)建Maven項目,添加依賴,并檢查Hadoop重啟和端口轉發(fā),提供test.bat文件,通過修改IP簡化使用過程
    2024-11-11
  • 分享7款開源Java反編譯工具

    分享7款開源Java反編譯工具

    今天我們要來分享一些關于Java的反編譯工具,反編譯聽起來是一個非常高上大的技術詞匯,通俗的說,反編譯是一個對目標可執(zhí)行程序進行逆向分析,從而得到原始代碼的過程。尤其是像.NET、Java這樣的運行在虛擬機上的編程語言,更容易進行反編譯得到源代碼
    2014-09-09
  • spring cloud實現前端跨域問題的解決方案

    spring cloud實現前端跨域問題的解決方案

    這篇文章主要介紹了 spring cloud實現前端跨域問題的解決方案,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01
  • Spring Cloud Zuul集成Swagger實現過程解析

    Spring Cloud Zuul集成Swagger實現過程解析

    這篇文章主要介紹了Spring Cloud Zuul集成Swagger實現過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-11-11
  • SpringBoot+MyBatis-Plus+Velocity實現代碼自動生成

    SpringBoot+MyBatis-Plus+Velocity實現代碼自動生成

    本文主要介紹了使用SpringBoot、MyBatis-Plus和Velocity模板引擎實現代碼自動生成器,該生成器能夠根據數據庫表結構自動生成增刪改查操作的代碼,感興趣的可以了解一下
    2025-03-03
  • Spring與Redis集成的正確方式流程詳解

    Spring與Redis集成的正確方式流程詳解

    這篇文章主要為大家介紹了Spring與Redis集成的正確方式流程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-06-06
  • RabbitMQ死信機制實現延遲隊列的實戰(zhàn)

    RabbitMQ死信機制實現延遲隊列的實戰(zhàn)

    本文主要介紹了RabbitMQ死信機制實現延遲隊列的實戰(zhàn),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11

最新評論

正阳县| 漯河市| 磐石市| 锡林郭勒盟| 治多县| 巫山县| 且末县| 镇安县| 鄂托克前旗| 育儿| 城口县| 黎平县| 拉孜县| 桐梓县| 广东省| 红河县| 新乡县| 遂川县| 金山区| 理塘县| 安徽省| 延庆县| 平潭县| 石狮市| 大渡口区| 永年县| 奉新县| 叙永县| 佛冈县| 灵丘县| 云和县| 泰来县| 天等县| 循化| 汽车| 高陵县| 城市| 陈巴尔虎旗| 玉门市| 萨嘎县| 大悟县|