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 看到线程的详细信息