Arthas能做什么
当我们的项目上线后可能遇到以下问题:
- 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
- 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
- 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
- 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
- 是否有一个全局视角来查看系统的运行状况?
- 有什么办法可以监控到JVM的实时运行状态?
- 怎么快速定位应用的热点,生成火焰图?
- 怎样直接从JVM内查找某个类的实例?
一般通过JDK自带的诊断工具去排查问题,不仅不好看而且需要记得很多的命令,而Arthas 支持JDK 6+,支持Linux/Mac/Windows,采用命令行交互模式,同时提供丰富的 Tab 自动补全功能,进一步方便进行问题的定位和诊断。
官方文档:https://arthas.aliyun.com/doc/
准备
Arthas其实就是一个 jar 包,不需要安装,在GitHub可以下载,同时我也准备了Arthas 3.5.4版本(提取码:udhi)。
官方推荐使用arthas-boot ,我们下载之后解压,如下:
启动
通过以下命令启动:
java -jar arthas-boot.jar
启动之后需要我们选择应用Java进程,我们这里选择 1 ,就成功启动了:
常用命令
在官方文档的进阶使用介绍了 Arthas 的命令,我们也可以使用 help 查看帮助(全英文,我看不懂)。
因为是全英文,如果英语不好的人只能望而却步了,但是看官方文档也是十分的方便。
当前系统的实时数据面板。
注意在 arthas 中,有 tab 键填充功能,如果你只记得命令的开头几个字母,你可以 tab 补齐,所以比较好用。但是这个界面是实时刷新的,一般 5s 刷新一次,使用 q 键退出刷新(没有退出 arthas,如果要退出,使用ctrl+c )。
这个命令和 jstack 很相似,但是功能更加强大,主要是查看当前 JVM 的线程堆栈信息。
参数名称 | 参数说明 |
---|
id | 线程id | -n | 指定最忙的前 n 个线程并打印堆栈 | -b | 找出当前阻塞其他线程的线程 | -i value | 指定cpu使用率统计的采样间隔,单位为毫秒,默认值为200 | -all | 显示所有匹配的线程 |
thread -i 1000 -n 3
每过 1000 毫秒进行采样,显示最占 CPU 时间的前 3 个线程。
thread –b
找出阻塞当前线程的线程。
如下面一段代码:
/**
* 类说明:演示死锁的产生,2个线程分别持有自己的锁,在不释放的情况下又想去获取对方的锁
*/
public class NormalDeadLock {
private static Object lock1 = new Object();//第一个锁
private static Object lock2 = new Object();//第二个锁
//第一个拿锁的方法
private static void lock1Do() throws InterruptedException {
String threadName = Thread.currentThread().getName();
synchronized (lock1) {
System.out.println(threadName + " get lock1");
Thread.sleep(100);
synchronized (lock2) {
System.out.println(threadName + " get lock2");
}
}
}
//第二个拿锁的方法
private static void lock2Do() throws InterruptedException {
String threadName = Thread.currentThread().getName();
synchronized (lock2) {
System.out.println(threadName + " get lock2");
Thread.sleep(100);
synchronized (lock1) {
System.out.println(threadName + " get lock1");
}
}
}
//子线程代表lock2
private static class Lock2 extends Thread {
private String name;
public Lock2(String name) {
this.name = name;
}
@Override
public void run() {
Thread.currentThread().setName(name);
try {
lock1Do();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
//主线程代表lock1
Thread.currentThread().setName("lock1");
Lock2 lock2 = new Lock2("lock2");
lock2.start();
lock2Do();
}
}
如果有死锁,会有红色的字提醒着,这个阻塞的线程已经被另外一个线程,如下:
thread --state WAITING
查看处于等待状态的线程。
查看当前JVM信息。
反编译指定已加载类的,可以查看代码是否提交更新或者在排错的时候查看别人写的代码。
命令:jad 指定的类 ,可用tab 补齐。
使用 trace 命令可以跟踪统计方法耗时。
比如使用一个 SpringBoot 项目,控制层 getOrder 方法调用了 orderService.getOrder(orderId) ,这个方法中分别进行 check、service、redis、mysql 等操作。就可以根据这个命令跟踪出来哪里的耗时最长。因此trace 能方便的帮助你定位和发现因 RT (Response Time,响应时间。一般系统RT 100ms 以内是比较正常的,300ms 勉强可以接受,1s 以上的话自己看着办吧。) 高而导致的性能问题缺陷,但其每次只能跟踪一级方法的调用链路。
栗子:
@RestController
@RequestMapping("/trace")
public class TraceController {
@RequestMapping("/getOrder")
public String getOrder(@RequestParam("orderId") String order) {
StringBuffer buffer = new StringBuffer();
//模拟check操作
String check = check(order);
String service = service(order);
String redis = redis(order);
String mysql = mysql(order);
buffer.append(check).append(service).append(redis).append(mysql);
return buffer.toString();
}
//检查订单编号是否正确
public String check(String order) {
try {
Thread.sleep(50);
return "订单编号check正常</br>";
} catch (InterruptedException e) {
e.printStackTrace();
}
return "fail";
}
//模拟业务操作
public String service(String order) {
try {
Thread.sleep(60);
return "通过订单编号业务操作service正常</br>";
} catch (InterruptedException e) {
e.printStackTrace();
}
return "fail";
}
//模拟redis查询
public String redis(String order) {
try {
Thread.sleep(30);
return "通过订单编号查询redis正常</br>";
} catch (InterruptedException e) {
e.printStackTrace();
}
return "fail";
}
//模拟mysql查询
public String mysql(String order) {
try {
Thread.sleep(30);
return "通过订单编号查询mysql正常</br>";
} catch (InterruptedException e) {
e.printStackTrace();
}
return "fail";
}
}
访问:http://localhost:8080/trace/getOrder?orderId=2
通过trace 命令查看:
方法执行监控。如每 5 秒统计一次某个类的某个方法的方法执行情况。
观察方法的入参出参信息。如:返回值、抛出异常、入参。
还是上面的代码,我们查看方法的入参和返回值可以这样:
watch cn.javatv.demo.controller.TraceController getOrder '{params[0],returnObj}'
总结
Arthas 是一个很优秀的 java 诊断工具,无论是安装还是使用都很简洁,这里只是列出了部分,如果你需要学习使用,建议查看官方文档和手动尝试。
Arthas命令列表:
参考:arthas使用介绍
|