Arthas線上問題排查


Arthas 使用場景

  1. 是否有一個全局視角來查看系統的運行狀況?
  2. 為什么 CPU 又升高了,到底是哪里占用了 CPU ?
  3. 運行的多線程有死鎖嗎?有阻塞嗎?
  4. 程序運行耗時很長,是哪里耗時比較長呢?如何監測呢?
  5. 這個類從哪個 jar 包加載的?為什么會報各種類相關的 Exception?
  6. 我改的代碼為什么沒有執行到?難道是我沒 commit?分支搞錯了?
  7. 遇到問題無法在線上 debug,難道只能通過加日志再重新發布嗎?
  8. 有什么辦法可以監控到 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    看到線程的詳細信息

死鎖

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM