作者 | 汪吉
【Arthas 官方社區正在舉行徵文活動,參加即有獎品拿~點擊投稿】
一、入門步驟
1. 安裝
https://arthas.gitee.io/install-detail.html
上述命令會下載啟動腳本文件 as.sh
到當前目錄:
curl -L https://alibaba.github.io/arthas/install.sh | sh
or
as.sh 啟動:
curl -sk https://arthas.gitee.io/arthas-boot.jar -o ~/.arthas-boot.jar && echo "alias as.sh='java -jar ~/.arthas-boot.jar --repo-mirror aliyun --use-http'" >> ~/.bashrc && source ~/.bashrc
2. 在線教程體驗
https://alibaba.github.io/arthas/arthas-tutorials?language=cn
當然也可以自己本地體驗一下~自己通過下載一個 arthas-idea-plugin 的體驗 demo 直接本地上手。
https://github.com/WangJi92/arthas-plugin-demo
全局命令說明
- -x 是展示結果屬性遍歷深度,默認為 1
- -n 是執行的次數 ,q 退出
- -c classloader 的hash值
- 退出 q ,關閉 stop
3. 瞭解最常用的trace、watch的功能
watch和trace 是arthas 診斷中對於開發人員解決線上的問題最常用的功能!
trace
基本示例
trace com.wangji92.arthas.plugin.demo.controller.CommonController getRandomInteger -n 5 '1==1'
https://arthas.gitee.io/trace.html
- 性能優化~
- 調用的這個方法,走的具體流程是咋樣的!可以通過調用鏈看出來。
- 有異常了可以查看異常的堆棧。
高級的功能
trace命令只會trace匹配到的函數裡的子調用,並不會向下trace多層。因為trace是代價比較貴的,多層trace可能會導致最終要trace的類和函數非常多。
trace -E xxxClassA|xxxClassB method1 | method2
trace -E com.wangji92.arthas.plugin.demo.controller.CommonController|com.wangji92.arthas.plugin.demo.service.ArthasTestService traceE|doTraceE -n 5 '1==1'
watch
https://arthas.gitee.io/watch.html
wathc 從字面上理解就是觀察值的信息,可以查看入參、返回值、異常、可以執行表達式獲取靜態變量、target.xxx調用目標實施的字段、方法等等都行~只要你想得到沒有做不到的~
基本示例
watch com.wangji92.arthas.plugin.demo.controller.CommonController traceE '{params,returnObj,throwExp}' -n 5 -x 3 '1==1'
4、arthas 表達式核心變量
public class Advice {
private final ClassLoader loader;
private final Class<?> clazz;
private final ArthasMethod method;
private final Object target;
private final Object[] params;
private final Object returnObj;
private final Throwable throwExp;
private final boolean isBefore;
private final boolean isThrow;
private final boolean isReturn;
// getter/setter
}
從watch 和 trace 中看到 後面的 '1==1' 執行的是一個條件表達式 當值為true 的時候通過執行了一個ognl 表達式 ,watch 觀察 params,returnObj,throwExp 入參、返回值、是否異常 這個也是一個表達式,那麼這個到底是咋回事?
spring el 表達式
沒有學習過ognl 使用多年的spring 一定知道他的el 表達式,el 表達式中也有一種概念叫做【Context 上下文,和表達式】 如下所示,因為有了simple這個上下文 才能解析 "booleanList[0]" 這個腳本的含義~ 這個很熟悉,很好理解,那麼ognl 表達式一樣不難了。
class Simple {
public List<Boolean> booleanList = new ArrayList<Boolean>();
}
Simple simple = new Simple();
simple.booleanList.add(true);
StandardEvaluationContext simpleContext = new StandardEvaluationContext(simple);
// false is passed in here as a string. SpEL and the conversion service will
// correctly recognize that it needs to be a Boolean and convert it
parser.parseExpression("booleanList[0]").setValue(simpleContext, "false");
// b will be false
Boolean b = simple.booleanList.get(0);
ognl 表達式
arthas 也是一樣的,只是使用了一個叫做ognl的腳本,核心變量就是他的上下文,可以直接獲取到這些字段。watch 觀察的這幾個字段 params,returnObj,throwExp 也就是我們所謂的上下文的概念,觀察參數、返回值、和異常的信息。
如下是arthas 源碼中 表達式評估和watch 觀察值執行的代碼!Advice 就是一個上下文,這裡還增加了一個變量 const。知道了這些那不是很簡單??
com.taobao.arthas.core.advisor.ReflectAdviceListenerAdapter#isConditionMet
/**
* 判斷條件是否滿足,滿足的情況下需要輸出結果
* @param conditionExpress 條件表達式
* @param advice 當前的advice對象
* @param cost 本次執行的耗時
* @return true 如果條件表達式滿足
*/
protected boolean isConditionMet(String conditionExpress, Advice advice, double cost) throws ExpressException {
return StringUtils.isEmpty(conditionExpress) ||
ExpressFactory.threadLocalExpress(advice).bind(Constants.COST_VARIABLE, cost).is(conditionExpress);
}
protected Object getExpressionResult(String express, Advice advice, double cost) throws ExpressException {
return ExpressFactory.threadLocalExpress(advice)
.bind(Constants.COST_VARIABLE, cost).get(express);
}
表達式實踐
arthas 群經常有人問重載方法如何判斷,無非就是評估條件? 參數的個數、第一個參數是什麼?返回值的類型等等都可以作為你評估的條件。如下的watch 前面的一段是觀察的值、後面這一段是表達式評估 ,滿足了條件才執行。
入參長度大於0
watch com.wangji92.arthas.plugin.demo.controller.CommonController traceE '{params,returnObj,throwExp}' -n 5 -x 3 'params.length >0'
返回值為String 且長度大於5
watch com.wangji92.arthas.plugin.demo.controller.CommonController traceE '{params,returnObj,throwExp}' -n 5 -x 3 'returnObj instanceof java.lang.String && returnObj.length>5'
條件表達式+異步任務
- 只有特定的場景才會有bug ,如何排查bug?
- 一天只出現一兩次如何解決?
條件表達式主要是用來過濾使用,比如某些場景只是在特定的參數才會出現,肯能會花費很多的時間去等待,這個時候可以使用條件表達式過濾 +異步任務更多參考博客
5、ognl 表達式
https://arthas.gitee.io/ognl.html 從上面看,ognl 在watch、trace上面無所不能啊,其實還有tt 也是 使用ognl 表達式執行邏輯的. @xxxClas@xxxStaticField 是靜態變量的語法糖 ognl的,好好看一下官方的文檔。OGNL特殊用法請參考:https://github.com/alibaba/arthas/issues/71
獲取靜態變量
靜態變量由於 一個jvm 中可能被多個classloader加載,jvm 認定為一個實例是一個classloader加載哦,所以需要知道當前靜態類的hash 值(sc -d com.wangji92.arthas.plugin.demo.controller.StaticTest)可以通過這個命令獲取。
ognl -x 3 '@com.wangji92.arthas.plugin.demo.controller.StaticTest@INVOKE_STATIC_DOUBLE' -c e374b99
調用spring 方法?
watch 執行ognl 語法中獲取spring context 然後進行調用bean的方法
watch -x 3 -n 1 org.springframework.web.servlet.DispatcherServlet doDispatch '@org.springframework.web.context.support.WebApplicationContextUtils@getWebApplicationContext(params[0].getServletContext()).getBean("commonController").getRandomInteger()'
ognl 執行靜態的一個spring context 然後調用bean 的方法
ognl -x 3 '#springContext=@com.wangji92.arthas.plugin.demo.common.ApplicationContextProvider@context,#springContext.getBean("commonController").getRandomInteger()' -c e374b99
有沒有起飛的感覺,無所不能!前提是你要掌握一些ognl的一些簡單的語法!
6、完畢
對於線上排查問題,我感覺這幾個命令夠你用了,還有一些其他的反編譯、火焰圖、.. 時間隧道、logger 等級修改,jvm環境信息等等感覺是有頻率都沒有上面的高,畢竟jvm信息有專門的監控~即使沒有arthas 你也可以找到更好的工具去分析堆棧,jvm故障。
一些特殊的用戶案列值得學習思考: https://github.com/alibaba/arthas/issues?q=label%3Auser-case
完了?
啊?這麼多命令 記不住啊 還有一些高級的ognl的語法涼了... 讓你獲取一下所有的spring的環境變量咋辦?trace、watch 這兩個命令我還沒有體驗夠呢?更加高級的讓我如何是好啊!好了,請看下文。
二、進階
前提
前提是你對於arthas 有了大概的理解,基本上的命令都有點概念了,ognl 簡單的語法能夠看懂了.. 簡單的條件表達式會用了。 之前我們所過arthas的命令這麼多 要記住小本本少不了啊!難受想哭~ 不要急,汪小哥來給你解決問題!
目前Arthas 官方的工具還不夠足夠的簡單,需要記住一些命令,特別是一些擴展性特別強的高級語法,比如ognl獲取spring context 為所欲為,watch、trace 不夠簡單,需要構造一些命令工具的信息,因此只需要一個能夠簡單處理字符串信息的插件即可使用。當在處理線上問題的時候需要最快速、最便捷的命令,因此arthas idea 插件還是有存在的意義和價值的。
arthas idea plugin
這個插件的意義不是處理協議層面的問題,主要解決命令生成的問題,由於工程在idea 裡面管理,你想想你要watch 哪個類,這個插件是知道的,幫助你更方便、更加快捷的構建命令。使用arthas idea 插件 這一點一定要理解哦!主要解決你如何構造命令的問題! 更多查看文檔
解決的問題
- spring 環境變量優先級問題
- 獲取靜態變量
- 火焰圖集成
- logger 命令集成
- 反編譯集成
- trace -E 集成
- tt 集成
....... 基本上你能夠在arths 上面看到的功能都集成到了這個上面!直接在idea 裡面搜索arths idea 即可安裝。
常用特殊用法問題
靜態變量
可以直接獲取 ognl 獲取
ognl -x 3 '@com.wangji92.arthas.plugin.demo.controller.StaticTest@INVOKE_STATIC_DOUBLE' -c e374b99
可以通過watch 獲取 (光標放置在字段上)
watch com.wangji92.arthas.plugin.demo.controller.StaticTest * '{params,returnObj,throwExp,@com.wangji92.arthas.plugin.demo.controller.StaticTest@INVOKE_STATIC_DOUBLE}' -n 5 -x 3 '1==1'
一般的變量
可以通過spring context.getBean().field 獲取(這個是要配置一個靜態的spring context 看使用文檔)
tt 、watch 也是可以的哦~ 一樣的原理
ognl -x 3 '#springContext=@com.wangji92.arthas.plugin.demo.common.ApplicationContextProvider@context,#springContext.getBean("staticTest").filedValue' -c e374b99
watch 獲取 放置在字段上即可
watch com.wangji92.arthas.plugin.demo.controller.StaticTest * '{params,returnObj,throwExp,target.filedValue}' -n 5 -x 3 'method.initMethod(),method.constructor!=null || [email protected]@isStatic(method.method.getModifiers())'
選擇的配置項的值
springContext.getEnvironment() (這個是要配置一個靜態的spring context 看使用文檔)
ognl -x 3 '#springContext=@com.wangji92.arthas.plugin.demo.common.ApplicationContextProvider@context,#springContext.getEnvironment().getProperty("custom.name")' -c e374b99
獲取所有的配置項的值
watch 獲取spring context tt 、static 也是可以的哦~ 一樣的原理
watch -x 3 -n 1 org.springframework.web.servlet.DispatcherServlet doDispatch '#springContext=@org.springframework.web.context.support.WebApplicationContextUtils@getWebApplicationContext(params[0].getServletContext()),#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'
視頻
有興趣可以看一下視頻~ 操作起來更流暢,基本上不用記憶啥。 arthas 入門到精通最佳實踐
三、更多
還想了解更多關於arthas-idea-plugin 的內容可以聯繫我 可以通過 右鍵查看arthas-idea-help 找到代碼地址和使用說明文檔,更重要的是提一下好的idea 讓arthas的使用更加的方便哦!插件地址: https://plugins.jetbrains.com/plugin/13581-arthas-idea
Arthas 徵文活動火熱進行中
Arthas 官方正在舉行徵文活動,如果你有:
- 使用 Arthas 排查過的問題
- 對 Arthas 進行源碼解讀
- 對 Arthas 提出建議
- 不限,其它與 Arthas 有關的內容
歡迎參加徵文活動,還有獎品拿哦~點擊投稿
“阿里巴巴雲原生關注微服務、Serverless、容器、Service Mesh 等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,做最懂雲原生開發者的公眾號。”