1. 简介

Arthas 是Alibaba开源的Java诊断工具, 支持以下功能:

  • 实时查看JVM进程信息, 包括CPU利用率, 内存使用分布, GC情况等.

  • 实时查看当前加载的类信息, 支持class文件反编译.

  • 跟踪方法调用, 包括调用栈, 方法参数, 返回值详情等等.

  • 收集方法统计耗时.

  • 支持远程连接.

  • …​

2. 安装

2.1. 物理机

在物理机上下载Arthas的jar包, 直接启动, 连接本机的Java进程.

curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar

2.2. Dockerfile集成

将Arthas的jar包直接安装到镜像中, 可以直接在容器中启动Arthas.

Dockerfile
FROM openjdk:8-alpine
COPY --from=hengyunabc/arthas:latest /opt/arthas /opt/arthas

2.3. C/S式集成

Arthas Tunnel Client 集成到项目中, 通过统一的 Arthas Tunnel Server 来访问各个Java进程.

2.3.1. 启动tunnel server

wget https://github.com/alibaba/arthas/releases/download/arthas-all-3.5.0/arthas-tunnel-server-3.5.0-fatjar.jar
java -jar arthas-tunnel-server-3.5.0-fatjar.jar --server.port=8000 --arthas.server.port=7777

2.3.2. 项目集成tunnel client

pom.xml
        <dependency>
            <groupId>com.taobao.arthas</groupId>
            <artifactId>arthas-spring-boot-starter</artifactId>
            <version>${arthas.version}</version>
        </dependency>

2.3.3. 项目配置client信息

application.yml
spring:
  application:
    name: web-demo
arthas:
  tunnel-server: ws://127.0.0.1:7777/ws
  agent-id: ${spring.application.name}#${random.value}
  telnet-port: -1
  http-port: -1

2.3.4. 访问server

填入AgentId, 即可连接到不同的Java进程.

3. 使用

4. 原理

通过Java Agent机制将Arthas连接到指定的JVM进程, 使用Instrument的API读写该JVM加载的类的字节码.

4.1. Java agent

4.1.1. 两种加载Agent的方式

  • 在JVM启动的时候通过启动参数加载: java -javaagent:<jarpath>[=<options>] . 加载完agent后会执行 public static void premain(String agentArgs, Instrumentation inst) 方法.

  • 在JVM启动后, 通过Attach API连接到该进程, 然后加载agent jar包, 加载完agent后会执行 public static void agentmain(String agentArgs, Instrumentation inst) 方法.

4.2. Java instrument

Instrumentation.java
public interface Instrumentation {

    /**
     * 注册一个类文件转换器,可以读写类文件字节码
     */
    void addTransformer(ClassFileTransformer transformer, boolean canRetransform);

    /**
     * 重新加载JVM已经加载过的类
     */
    void retransformClasses(Class<?>... classes) throws UnmodifiableClassException;

    /**
     * 获取当前JVM加载的所有类
     */
    Class[] getAllLoadedClasses();

}