Arthas使用实践
一、官方文档
开源地址:https://github.com/alibaba/arthas
官方文档:https://alibaba.github.io/arthas
二、命令介绍
1. Dashboard 实时数据 [i:]刷新实时数据的时间间隔 (ms),默认5000ms [n:]刷新实时数据的次数 2. Thread 查看当前线程信息,查看线程的堆栈 id 线程id [n:] 指定最忙的前N个线程并打印堆栈 [b] 找出当前阻塞其他线程的线程 [i <value>] 指定cpu占比统计的采样间隔,单位为毫秒 3. Jad 反编译指定已加载类的源码 class-pattern 类名表达式匹配 [c:] 类所属 ClassLoader 的 hashcode [E] 开启正则表达式匹配,默认为通配符匹配 4. Jvm THREAD相关 COUNT: JVM当前活跃的线程数 DAEMON-COUNT: JVM当前活跃的守护线程数 PEAK-COUNT: 从JVM启动开始曾经活着的最大线程数 STARTED-COUNT: 从JVM启动开始总共启动过的线程次数 DEADLOCK-COUNT: JVM当前死锁的线程数 文件描述符相关 MAX-FILE-DESCRIPTOR-COUNT:JVM进程最大可以打开的文件描述符数 OPEN-FILE-DESCRIPTOR-COUNT:JVM当前打开的文件描述符数 5. Classloader [l] 按类加载实例进行统计 [t] 打印所有ClassLoader的继承树 [a] 列出所有ClassLoader加载的类,请谨慎使用 [c:] ClassLoader的hashcode [classLoaderClass:] 指定执行表达式的 ClassLoader 的 class name [c: r:] 用ClassLoader去查找resource [c: load:] 用ClassLoader去加载指定的类 6. Logger logger --name ROOT --level debug 修改日志级别 logger -n org.springframework.web 查看指定名字的logger信息 logger -c 2a139a55 查看指定classloader的logger信息 7. Sysprop 查看当前JVM的系统属性 Sysprop 查看所有 Sysprop <property-name> <property-value> 修改单个 8. Sysenv 查看当前JVM的环境属性 Sysenv 查看所有 Sysenv <env-name> 查看单个 9. Vmoption 查看,更新VM诊断相关的参数 vmoption [name] [value] 更新 10.Perfcount 查看当前JVM的 Perf Counter性能统计信息 11. Mbean 便捷的查看或监控 Mbean 的属性信息 MBean其实也是JavaBean的一种,但是MBean往往代表的是JMX中的一种可以被管理的资源。 MXBean与MBean的区别主要是在于在接口中会引用到一些其他类型的类时,其表现方式的不一样。在MXBean中,如果一个MXBean的接口定义了一个属性是一个自定义类型,如MemoryMXBean中定义了heapMemoryUsage属性,这个属性是MemoryUsage类型的,当JMX使用这个MXBean时,这个MemoryUsage就会被转换成一种标准的类型,这些类型被称为开放类型,是定义在javax.management.openmbean包中的。而这个转换的规则是,如果是原生类型,如int或者是String,则不会有变化,但如果是其他自定义类型,则被转换成CompositeDataSupport类。 MBean, MXBean接口后缀,被实现类去掉后缀。 12. Ognl express 执行的表达式 [c:] 执行表达式的 ClassLoader 的 hashcode,默认值是SystemClassLoader [classLoaderClass:] 指定执行表达式的 ClassLoader 的 class name [x] 结果对象的展开层次,默认值1 查看静态变量,可调用静态方法 ognl '@com.shunwang.buss.agent.client.config.AgentApiConfig@APPLICATION_NAME‘ 执行多行表达式,赋值给临时变量,返回一个List: ognl '#value1=@System@getProperty("java.home"), #value2=@System@getProperty("java.runtime.name"), {#value1, #value2}' 13. Sc 查看JVM已加载的类信息 参数名称 参数说明 class-pattern 类名表达式匹配 method-pattern 方法名表达式匹配 [d] 输出当前类的详细信息,包括这个类所加载的原始文件来源、类的声明、加载的ClassLoader等详细信息。 如果一个类被多个ClassLoader所加载,则会出现多次 [E] 开启正则表达式匹配,默认为通配符匹配 [f] 输出当前类的成员变量信息(需要配合参数-d一起使用) [x:] 指定输出静态变量时属性的遍历深度,默认为 0,即直接使用 toString 输出 [c:] 指定class的 ClassLoader 的 hashcode [classLoaderClass:] 指定执行表达式的 ClassLoader 的 class name [n:] 具有详细信息的匹配类的最大数量(默认为100) 14. Sm 查看已加载类的方法信息 class-pattern 类名表达式匹配 method-pattern 方法名表达式匹配 [d] 展示每个方法的详细信息 [E] 开启正则表达式匹配,默认为通配符匹配 [c:] 指定class的 ClassLoader 的 hashcode [classLoaderClass:] 指定执行表达式的 ClassLoader 的 class name [n:] 具有详细信息的匹配类的最大数量(默认为100) 15. dump 已加载类的 bytecode 到特定目录 16. Heapdump 类似jmap命令的heap dump功能 heapdump --live /tmp/dump.hprof 只dump live对象 17. tt 方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测 -t 记录下来每次执行情况 -n 指定记录的次数 TIMESTAMP 方法执行的本机时间,记录了这个时间片段所发生的本机时间 IS-RET 方法是否以正常返回的形式结束 IS-EXP 方法是否以抛异常的形式结束 OBJECT 执行对象的hashCode() 解决方法重载: tt -t *Test print params.length==1 tt -t *Test print 'params[1] instanceof Integer' 解决指定参数: tt -t *Test print params[0].mobile=="13989838402" 构成条件表达式的 Advice 对象: https://arthas.aliyun.com/doc/advice-class.html tt -l 检索调用记录 tt -s 'method.name=="primeFactors"' -i [index] 查看详细信息 tt -i 1004 -p 重做一次调用(threadlocal信息会丢失,引用对象入参可能会变更) 18. stack 输出当前方法被调用的调用路径 class-pattern 类名表达式匹配 method-pattern 方法名表达式匹配 condition-express 条件表达式 [E] 开启正则表达式匹配,默认为通配符匹配 [n:] 执行次数限制 例子: stack demo.Test test 'params[0]<0' -n 2 执行时间过滤:'#cost>5' 19. trace 方法内部调用路径,并输出方法路径上的每个节点上耗时 class-pattern 类名表达式匹配 method-pattern 方法名表达式匹配 condition-express 条件表达式 [E] 开启正则表达式匹配,默认为通配符匹配 [n:] 命令执行次数 #cost 方法执行耗时 深入子函数: a.新开终端telnet localhost 3658 b.trace demo.MathGame primeFactors --listenerId 3 20. monitor 方法实时监控 monitor -c 5 demo.Test test 21. watch 方法执行数据观测 class-pattern 类名表达式匹配 method-pattern 方法名表达式匹配 express 观察表达式 condition-express 条件表达式 [b] 在方法调用之前观察 [e] 在方法异常之后观察 [s] 在方法返回之后观察 [f] 在方法结束之后(正常返回和异常返回)观察 [E] 开启正则表达式匹配,默认为通配符匹配 [x:] 指定输出结果的属性遍历深度,默认为 1 观察出参:watch demo.Test test "{params,returnObj}" -x 2 入参: -b 条件表达式:watch demo.Test test "{params[0],target}" "params[0]<0" 异常: "{params[0],throwExp}" -e 22. profiler 不断采样生成火焰图 23.支持基本命令:cat,echo,grep,pwd 24. tee 类似传统的tee命令, 用于读取标准输入的数据,并将其内容输出成文件。 sysprop | tee /path/to/logfile | grep java sysprop | tee -a /path/to/logfile | grep java 25. options 全局开关 26. 基础命令 reset——重置增强类,将被 Arthas 增强过的类全部还原,Arthas 服务端关闭时会重置所有增强过的类 history——打印命令历史 quit——退出当前 Arthas 客户端,其他 Arthas 客户端不受影响 stop——关闭 Arthas 服务端,所有 Arthas 客户端全部退出 27. mc Memory Compiler/内存编译器,编译.java文件生成.class。 -c 指定classloader -d 指定输出目录 28. redefine 加载外部的.class文件,redefine jvm已加载的类。 注意, redefine后的原来的类不能恢复.不允许新增加field/method,正在跑的函数,没有退出不能生效. reset命令对redefine的类无效。如果想重置,需要redefine原始的字节码 redefine命令和jad/watch/trace/monitor/tt等命令会冲突。执行完redefine之后,如果再执行上面提到的命令,则会把redefine的字节码重置。
三、如何开始
- 下载启动:
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar
2. 远程连接:arthas tunnel server
wget https://github.com/alibaba/arthas/releases/download/arthas-all-3.3.9/arthas-tunnel-server-3.3.9.jar
java -jar arthas-tunnel-server.jar
默认情况下,arthas tunnel server的web端口是8080,arthas agent连接的端口是7777。
通过Spring Boot的Endpoint,可以查看到具体的连接信息: http://localhost:8080/actuator/arthas
-
-
启动arthas时连接到tunnel server
-
as.sh --tunnel-server 'ws://192.168.42.157:7777/ws'
-
-
springboot应用
-
依赖:
启动监听自身:
<dependency>
<groupId>com.taobao.arthas</groupId>
<artifactId>arthas-spring-boot-starter</artifactId>
<version>3.3.9</version>
</dependency>
配置:连接到tunnel server
arthas.agent-id=sadsadsada
arthas.tunnel-server=ws://192.168.42.157:7777/ws
四、实践
- 实时代码更新:
jad --source-only demo.Test > /tmp/Test.java
修改Test.java
sc -d *Test | grep classLoaderHash 查看类加载hash
mc -c [hash值] /tmp/Test.java -d /tmp 编译
redefine /tmp/demo/Test.class 生效
2. 修改属性值:
3. 修改日志属性:
ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader '@com.example.demo.arthas.user.UserController@logger.setLevel(@ch.qos.logback.classic.Level@DEBUG)'
4. 追踪排查问题:
trace javax.servlet.Filter * 追踪所有Filter函数
trace javax.servlet.Servlet * > /tmp/servlet.txt
401:
Access is denied
throw:
5. 查看5秒内的CPU使用率top n线程栈
thread -n 3 -i 5000
查找线程是否有阻塞
thread -b