Arthas 使用場景
- 是否有一個全局視角來查看系統的運行狀況?
- 為什么 CPU 又升高了,到底是哪里占用了 CPU ?
- 運行的多線程有死鎖嗎?有阻塞嗎?
- 程序運行耗時很長,是哪里耗時比較長呢?如何監測呢?
- 這個類從哪個 jar 包加載的?為什么會報各種類相關的 Exception?
- 我改的代碼為什么沒有執行到?難道是我沒 commit?分支搞錯了?
- 遇到問題無法在線上 debug,難道只能通過加日志再重新發布嗎?
- 有什么辦法可以監控到 JVM 的實時運行狀態?
下載安裝
1. 下載 wget https://arthas.gitee.io/arthas-boot.jar
2. 啟動 java -jar arthas-boot.jar --target-ip 192.168.200.100 --http-port 8563 PID
默認arthas只能本地訪問,上面通過指定ip 和 端口就能遠程監控了。
常用指令 cls 清空面板 ;exit 退出當前會話 ;stop 關閉arthas
常用命令
后續再補吧
實戰演示
定位調用鏈路
比如現在有一個請求過來,我要查看它的調用鏈路,每個方法請求時長,以及每個方法的請求參數和返回值來分析問題。

@RestController public class UserController { @Autowired private UserService userService; @GetMapping("/test") public Map test(){ Map map = new HashMap(); map.put("code",1); map.put("data",userService.getUser()); map.put("msg","執行成功"); return map; } } @Service public class UserService { @Autowired private UserMapper userMapper; public User getUser(){ try { Thread.sleep(1000); }catch (Exception e){ } return userMapper.getUser(); } } @Service public class UserMapper { public User getUser(){ return new User(); } }

import com.wulei.entity.JsonResult; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.HashSet; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @RestController public class ArthasController { private static HashSet hashSet = new HashSet(); // 線程池,大小1 private static ExecutorService executorService = Executors.newFixedThreadPool(1); /** * 模擬 CPU 過高 */ @GetMapping("/cpu") public JsonResult cpu() { // 極度消耗CPU的線程 Thread thread = new Thread(() -> { while (true) { System.out.println("cpu start 100"); } }); // 添加到線程 executorService.submit(thread); // 普通消耗CPU的線程 for (int i = 0; i < 10; i++) { new Thread(() -> { while (true) { System.out.println("cpu start"); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } return new JsonResult(); } /** * 不斷的向 hashSet 集合添加數據 */ @GetMapping("/add") public JsonResult addHashSetThread() { // 初始化常量 new Thread(() -> { int count = 0; while (true) { try { hashSet.add("count" + count); Thread.sleep(10000); count++; } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); return new JsonResult(); } /** * 模擬線程阻塞,向已經滿了的線程池提交線程 */ @GetMapping("/thread") private JsonResult thread() { Thread thread = new Thread(() -> { while (true) { System.out.println("thread start"); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } }); // 添加到線程 executorService.submit(thread); return new JsonResult(); } /** * 死鎖 */ @GetMapping("/dead") private JsonResult deadThread() { /** 創建資源 */ Object resourceA = new Object(); Object resourceB = new Object(); // 創建線程 Thread threadA = new Thread(() -> { synchronized (resourceA) { System.out.println(Thread.currentThread() + " get ResourceA"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread() + "waiting get resourceB"); synchronized (resourceB) { System.out.println(Thread.currentThread() + " get resourceB"); } } }); Thread threadB = new Thread(() -> { synchronized (resourceB) { System.out.println(Thread.currentThread() + " get ResourceB"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread() + "waiting get resourceA"); synchronized (resourceA) { System.out.println(Thread.currentThread() + " get resourceA"); } } }); threadA.start(); threadB.start(); return new JsonResult(); } }
1. trace命令 追蹤調用鏈路,以及每個方法所用的時長。可以寫完整的路徑名稱,也可以使用通配符。
2. jad命令 反編譯代碼
3. watch命令 觀察方法的入參出參及異常
CPU占用過高
比如線上環境有的線程非常的消耗 CPU性能
,那么怎么找出來呢?
1. thread命令 查看cpu的占用率比
2 thread 線程id 看到線程的詳細信息
死鎖