当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决:
注: 以上内容来自官网
下载命令
curl -O https://arthas.aliyun.com/arthas-boot.jar
安装命令
java -jar arthas-boot.jar
//使用阿里云镜像下载arthas
java -jar arthas-boot.jar --repo-mirror aliyun --use-http
在安装之前需要启动一个java应用程序,否则会报下面的异常
[root@master arthas]# java -jar arthas-boot.jar --repo-mirror aliyun --use-http
[INFO] arthas-boot version: 3.4.5
[INFO] Can not find java process. Try to pass <pid> in command line.
Please select an available pid.
上面的方式比较麻烦,还需要手动安装arthas并attach应用程序。arthas提供了Spring Boot Starter,可以在应用启动后自动启动arthas,并attach当前应用的进程,只需要配置一下依赖包即可。
maven依赖:
<dependency>
<groupId>com.taobao.arthas</groupId>
<artifactId>arthas-spring-boot-starter</artifactId>
<version>3.4.5</version>
</dependency>
可以在application.properties中配置arthas需要的属性,例如:
arthas.appName=demo
//默认情况下,agentId会自动生成一个随机ID,如果配置了appName,agentId就是appName_随机Id
arthas.agentId=demo_123
一般开发人员没有线上机器的操作权限,而且现在都是分布式部署,一个服务会部署到多台机器上,操作起来也比较麻烦。因此,arthas提供了tunnel,可以远程操控多个agent。tunnel采用的WebSocket实现的,可以在浏览器里操作远程agent。
tunnel是一个SpringBoot应用,直接把jar包下载下来启动即可。
下载地址: arthas-tunnel-server
启动命令:
java -jar arthas-tunnel-server-3.4.6-fatjar.jar
web端的访问端口默认是8080,agent的连接端口默认是7777
在应用程序的application.properties中配置tunnel的服务地址
arthas.tunnelServer=ws://172.0.0.1:7777/ws
在浏览器中访问http://IP:8080/
在AgentId框里输入应用程序里配置的arthas.agentId=demo_123,点击Connect
http://IP:8080/actuator/arthas该路径可以查看到连接信息,用户名是arthas,密码在tunnel的启动日志里可以找到
arthas命令大全
jvm相关指标信息参见另一篇文章:JVM内存监控及故障分析
定义一个类:TestController
@RestController
public class TestController {
/**
* 内存泄漏
*/
@GetMapping("/memoryLeak")
public void memoryLeak() {
while (true) {
this.list();
}
}
static class MemoryLeakObject {
byte[] o = new byte[10 * 1024 * 1024];
}
static List<MemoryLeakObject> list = new ArrayList<>();
private void list() {
list.add(new MemoryLeakObject());
}
/**
* 死循环
*/
@GetMapping("/endlessLoop")
public void endlessLoop() {
Thread thread = new Thread(() -> {
while (true);
}, "endlessLoop");
thread.start();
}
/**
* 方法链路追踪
*/
@GetMapping("/trace")
public void trace() throws InterruptedException {
this.trace1();
}
private void trace1() throws InterruptedException {
System.out.println("======");
TimeUnit.SECONDS.sleep(2);
this.trace2();
}
private void trace2() throws InterruptedException {
System.out.println("******");
TimeUnit.SECONDS.sleep(3);
}
}
dashboard: 查看实时监控数据面板
如果执行了memoryLeak方法,可以很明显的看到内存的变化情况,此时内存已被撑满。
thread [ID]: 查看某个线程的栈信息
jad [类全路径]: 反编译类
thread -n [n]: 查看前n个最繁忙的线程
trace [class-pattern] [method-pattern]: 查看方法调用链路,能够查看每个方法的执行时间,但是每次只能查看一级调用,如下图
注意trace使用的是字节码增强技术,也就是给指定的方法插入了切面,因此诊断完时要执行stop命令,或对类执行reset命令
reset TestController