天天看點

Arthas神器實戰Arthas

Arthas神器實戰

  • Arthas
    • 0引言
    • 1安裝
    • 2常用指令
    • 3熱部署Java類

Arthas

0引言

當你遇到以下問題而束手無策時,Arthas或許可以幫助你:

  1. 這個類從哪個jar包加載的?為什麼會報各種類相關的Exception?
  2. 我改的代碼為何沒有執行?難道我沒有commit?版本不對?替換JAR再重新開機?
  3. 遇到問題無法線上上debug,難道隻能通過加日志再重新釋出嗎?
  4. 線上遇到某個使用者的資料處理有問題,但線上同樣無法debug,而線下複現成本巨大,頭疼?
  5. 是否有一個全局的視圖來檢視系統運作狀況?
  6. 有什麼辦法可以監控到JVM的實時運作狀态?
  7. 如何快速定位應用的熱點,生成火焰圖?

1安裝

Arthas神器實戰Arthas

根據推薦,使用如下指令啟動Arthas,

java -jar arthas-boot.jar

java -jar arthas-boot.jar ${pid}

Arthas神器實戰Arthas
針對docker容器内的安裝,需要傳入Arthas壓縮包
Arthas神器實戰Arthas

sudo docker cp /home/sunquan-temp/arthas-packaging-3.2.0-bin.zip ff32:/home

gunzip -d arthas-packaging-3.2.0-bin.zip

2常用指令

  1. dashboard

    針對程序目前内部情況的資訊概覽,其中包括線程、記憶體、運作時常量,如圖:

    Arthas神器實戰Arthas

3熱部署Java類

本節是介紹複用Arthas如何在不重新開機的情況下修改源碼并使其生效。以一個spring-boot項目為例。

@Api(tags = "使用者子產品")
@Controller
public class UserController {
    @ApiOperation(value = "使用者登入", notes = "随邊說點啥")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "mobile", value = "手機号", required = true, paramType = "query"),
            @ApiImplicitParam(name = "password", value = "密碼", required = true, paramType = "query"),
            //針對int類型要固定定義example
            @ApiImplicitParam(name = "age", value = "年齡", required = true, paramType = "query", example = "1", defaultValue = "1", dataType = "int")
    })
    @ApiResponses({
            @ApiResponse(code = 200, message = "請求成功"),
            @ApiResponse(code = 400, message = "請求參數沒填好"),
            @ApiResponse(code = 404, message = "請求路徑沒有或頁面跳轉路徑不對")
    })
    @ResponseBody
    @PostMapping("/login")
    public UserLoginVO login(@RequestParam String mobile, @RequestParam String password,
                             @RequestParam int age) {
        System.out.println(mobile + password + age);
        UserLoginVO userLoginVO = new UserLoginVO();
        userLoginVO.setPassword(password);
        userLoginVO.setUsername(mobile);
        //System.out.println("success");
        return userLoginVO;
    }
   }
           

通過請求最終傳回:

{

“username”: “18912345675”,

“password”: “bca”

}

此時需要在該方法中顯示列印一條success,在不重新開機服務情況下,通過Arthas步驟如下:

1、修改源碼,增加success列印,如果你已經有源碼,則可以在已有的源碼上修改,如果沒有,需要通過jad命名反編譯位元組碼為源碼,如

jad --source-only com.zte.sunquan.spring.ReadingListController > F:/1/ReadingListController.java

通過上述指令可以得到源碼

2、通過sc查詢該代碼在目前程序中的類加載器對象執行個體

sc -d com.zte.sunquan.spring.ReadingListController | grep classLoaderHash
Arthas神器實戰Arthas

3、使用mc反編譯修改後的類檔案

mc -c 2513c0f4 E:/01sq-code/demo-for-learing-sq/spring-demo/src/main/java/com/zte/sunquan/spring/UserController.java -d F:/1

ps.該指令中直接使用IDE中的類檔案,且在指定目錄生成位元組碼檔案

4、使用redefine指令重新加載編碼好的新位元組碼檔案

redefine F:/1/com/zte/sunquan/spring/UserController.class

ps.注意修改的JAVA類,不允許新增field/method,以及正在跑的函數,也不能有内部類,如未退出則不生效

結果:

再試觸發rest調用,發現控制台果然列印出了success

Arthas神器實戰Arthas