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

死锁

原文地址:https://www.cnblogs.com/wlwl/p/14262858.html