在阿里內部是如何 Debug 線上問題的?
在日常工作中我們經常會遇到一些線上異常的情況,而且有些問題只有在線上才會出現,由于環境和數據不一樣在本地和測試環境根本沒辦法復現,而且線上也沒有輸出日志,那么遇到這種情況我們往往要怎么去解決呢?
常規做法
如果實在遇到上面的情況,在本地和測試都無法復現,那最常規的做法就是拉個線上分支的版本,增加一些調試日志,然后再重新發布版本進行調試。運氣好加一次日志就可以找到問題,運氣不好的話可能還要發布好幾次才能定位到問題。
高級做法
下載安裝 arthas
Arthas 是阿里開源的一款線上監控診斷產品,通過全局視角實時查看應用 load、內存、gc、線程的狀態信息,并能在不修改應用代碼的情況下,對業務問題進行診斷,包括查看方法調用的出入參、異常,監測方法執行耗時,類加載信息等,大大提升線上問題排查效率。
上面的 Arthas 這款工具的官方介紹,從中我們可以看到這個工具可以查看方法的出入參,異常以及監測方法的耗時,我們排查問題的時候最重要的就是想知道一些方法的入參和返回,有了入參和返回的數據我們就可以模擬出具體的場景從而解決線上的問題。
注意這里說的方法不單單是外層的接口方法,任何 Service 層或者 RPC 層的方法都是可以的。之所以提出這一點是因為很多時候線上的接口都會有請求和結果的日志記錄,但是并沒有內部某個具體方法的入參和返回,而通過 Arthas 我們可以監控任何方法的入參和返回值。
我們可以在https://github.com/alibaba/arthas/releases 這個地址上下載具體的版本,下載下來就可以用,沒什么難度。接下來阿粉通過一個案例來帶大家使用一下 Arthas。
測試
首先我們啟動一個 Spring Boot 應用,并且對外一個 http 的接口,具體的 Controller 和 Service 代碼實現如下。
package com.example.demo.controller;
import com.example.demo.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@Autowired
private HelloService helloService;
@GetMapping(value = "/hello")
public String hello(@RequestParam("name") String name) {
return helloService.sayHello(name);
}
}
package com.example.demo.service;
import org.springframework.stereotype.Service;
@Service
public class HelloService {
public String sayHello(String name) {
String result = doSomething(name);
return "hello: " + result;
}
private String doSomething(String name) {
return name + " 歡迎關注 Java 極客技術";
}
}
上面的代碼非常簡單,對外暴露了一個 hello 接口,接收一個 name 參數,Service 中通過 sayHello 方法,調用了一個內部的 doSomething 方法。其中過后我們訪問 http://127.0.0.1:8080/hello?name=ziyou 可以看到如下的內容。
到這里都沒什么問題,但是我們想象一下,如果在某些 case doSomething 的方法比較復雜,我們想知道在執行 doSomething 方法的時候具體的入參和返回值是什么,這個時候我們要怎么辦呢?
當然如果采用上面的常規做法,增加一些日志,當然是可以,不過我們這里就來演示一下如何使用 Arthas 來實現這個效果。前面我們已經下載了 Arthas 了,下載完成后是一個壓縮包,解壓過后,可以通過命令java -jar arthas-boot.jar 來啟動 Arthas。效果如下
可以看到啟動過后 Arthas 會找到目前系統當中在運行的 Java 進程,我這里有四個進程,然后輸入我們要監控的進程編號,這里是 4,然后回車,接下來我們就進入了 Arthas 的界面。
接下來我們使用 Arthas 的 watch 命令來監控入參和返回值,完整的命令如下:watch com.example.demo.service.HelloService doSomething '{params,returnObj}
接下來我們再去訪問一下剛剛的接口,可以看到在終端上面有對應的數據輸出。
簡單解釋一下對應的命令和輸出的信息,watch 是 Arthas 提供的命令,后面根據第一個參數是完整的類路徑,第二個參數是我們要監控的方法名,第三個參數是一個表達是這里我們可以獲取入參以及返回值或者異常等信息,對應的取值有 params 數組形式,可以通過 params[0] 來獲取對應的屬性,returnObj 表示返回值,并且這兩個都是可以通過 .的形式,獲取下面屬性的值的。
watch 命令后面的第三個參數其實是一個 ognl 表達式,如下所示我們是可以做一些計算和邏輯處理的,這就帶來了很多高級的用法。Arthas的一些特殊用法文檔說明 https://github.com/alibaba/arthas/issues/71
總結
Arthas 除了 watch 之外還有很多其他的命令可以使用,比如 trace 可以統計每個方法執行的耗時,對于我們做一些性能優化有很大的幫助,還有比如支持熱部署的功能等。完整的命令和使用方式大家可以在這個網址找到 https://arthas.aliyun.com/doc/,并且這里還提供了一套在線演示的功能,可以在在線教程中通過終端依次親手執行每個命令來學習。官方提供了一個應用程序 math-game.jar 可以讓我們在線調試,感興趣的小伙伴可以去試一試。