當Dubbo遇上Arthas,會碰撞出什麼樣的火花? context.getBean("userServiceImpl").findUser(1) 獲取到userServiceImpl再執行一次調用

推薦閱讀:

Apache Dubbo是Alibaba開源的高性能RPC框架,在國內有非常多的用戶。

Arthas是Alibaba開源的應用診斷利器,9月份開源以來,Github Star數三個月超過6000。

當Dubbo遇上Arthas,會碰撞出什麼樣的火花呢?下面來分享Arthas排查Dubbo問題的一些經驗。

dubbo-arthas-demo

下面的排查分享基於這個dubbo-arthas-demo,非常簡單的一個應用,瀏覽器請求從Spring MVC到Dubbo Client,再發送到Dubbo Server。

Demo裏有兩個spring boot應用,可以先啓動server-demo,再啓動client-demo。

Client端:

Server端:

Arthas快速開始

啓動後,會列出所有的java進程,選擇1,然後回車,就會連接上ServerDemoApplication

Dubbo線上服務拋出異常,怎麼獲取調用參數?

當線上服務拋出異常時,最着急的是什麼參數導致了拋異常?

在demo裏,

訪問http://localhost:8080/user/0,UserServiceImpl就會拋出一個異常,因爲user id不合法。

在Arthas裏執行 watch com.example.UserService * -e -x 2 '{params,throwExp}' ,然後再次訪問,就可以看到watch命令把參數和異常都打印出來了。

怎樣線上調試Dubbo服務代碼?

在本地開發時,可能會用到熱部署工具,直接改代碼,不需要重啓應用。但是在線上環境,有沒有辦法直接動態調試代碼?比如增加日誌。

在Arthas裏,可以通過redefine命令來達到線上不重啓,動態更新代碼的效果。

比如我們修改下UserServiceImpl,用System.out打印出具體的User對象來:

本地編繹後,把

server-demo/target/classes/com/example/UserServiceImpl.class

傳到線上服務器,然後用redefine命令來更新代碼:

這樣子更新成功之後,訪問 http://localhost:8080/user/1,在ServerDemoApplication的控制檯裏就可以看到打印出了user信息。

怎樣動態修改Dubbo的logger級別?

在排查問題時,需要查看到更多的信息,如果可以把logger級別修改爲DEBUG,就非常有幫助。

ognl是apache開源的一個輕量級表達式引擎。下面通過Arthas裏的ognl命令來動態修改logger級別。

首先獲取Dubbo裏TraceFilter的一個logger對象,看下它的實現類,可以發現是log4j。

再用sc命令來查看具體從哪個jar包里加載的:

可以看到log4j是通過slf4j代理的。

那麼通過org.slf4j.LoggerFactory獲取root logger,再修改它的level:

可以看到修改之後,root logger的level變爲DEBUG。

怎樣減少測試小姐姐重複發請求的麻煩?

在平時開發時,可能需要測試小姐姐發請求過來聯調,但是我們在debug時,可能不小心直接跳過去了。這樣子就尷尬了,需要測試小姐姐再發請求過來。

Arthas裏提供了tt命令,可以減少這種麻煩,可以直接重放請求。

上面的tt -t命令捕獲到了3個請求。然後通過tt --play可以重放請求:

Dubbo運行時有哪些Filter? 耗時是多少?

Dubbo運行時會加載很多的Filter,那麼一個請求會經過哪些Filter處理,Filter裏的耗時又是多少呢?

通過Arthas的trace命令,可以很方便地知道Filter的信息,可以看到詳細的調用棧和耗時。

Dubbo動態代理是怎樣實現的?

  • .github.io/arthas/jad.html
  • com.alibaba.dubbo.common.bytecode.Wrapper

通過Arthas的jad命令,可以看到Dubbo通過javaassist動態生成的Wrappr類的代碼:

獲取Spring context

除了上面介紹的一些排查技巧,下面分享一個獲取Spring Context,然後“爲所欲爲”的例子。

在Dubbo裏有一個擴展

com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory,把Spring Context保存到了裏面。

因此,我們可以通過ognl命令獲取到。

  • [email protected] 獲取到SpringExtensionFactory裏保存的spring context對象
  • context.getBean("userServiceImpl").findUser(1) 獲取到userServiceImpl再執行一次調用

只要充分發揮想像力,組合Arthas裏的各種命令,可以發揮出神奇的效果。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章