安装启动方式
arthas只是诊断工具,诊断工具,诊断工具重要事情说3遍
包含
arthas .jar 诊断工具
webconsole (注册和代理)用于多个arthas项目。
下载地址 https://github.com/alibaba/arthas/releases
#启动方式
java -jar as.jar
./as.sh
./as bat
springboot 项目需要引入 2.0版本以上
<dependency>
<groupId>com.taobao.arthas</groupId>
<artifactId>arthas-spring-boot-starter</artifactId>
<version>3.3.9</version>
</dependency>
配置文件
arthas.agent-id=wodeguo
arthas.tunnel-server=ws://127.0.0.1:7777/ws ##webconsole address
webconsole web 地址 就是 ip:端口 但是那个页面有兼容问题,命令太长放不下,也看不见光标。
默认是8080 ,ip:8080 即可访问 webconsole ,这个也支持springsecurity集成管理
命令行连接webconsole
./as.sh --tunnel-server 'ws://127.0.0.1:7777/ws'
./as.sh --tunnel-server 'ws://127.0.0.1:7777/ws' --agent-id wodeguo
基础命令
- help 命令列表 tab补全 map窗口快捷键有冲突
dashboard (面板)
-
ID: Java级别的线程ID,注意这个ID不能跟jstack中的nativeID一一对
-
NAME: 线程名
-
GROUP: 线程组名
-
PRIORITY: 线程优先级, 1~10之间的数字,越大表示优先级越高
-
STATE: 线程的状态
-
CPU%:线程消耗的cpu占比,采样100ms,将所有线程在这100ms内的cpu使用量求和,再算出每个线程的cpu使用占比。
-
TIME:线程运行总时间,数据格式为分:秒
-
INTERRUPTED: 线程当前的中断位状态
-
DAEMON: 是否是daemon线程
线程
死锁
thread -b #查看死锁的线程信息 或者thread 里面statue 为lock
sysprop #程序环境一览
sysenv #jvm环境变量
线程信息查找
thread ##面板
thread 线程id|grep '查找内容'
thread -n 1 ##cpu前1位
环境命令,查找命令
sysprop #pcjava环境一览 可以改
sysenv #jvm环境 不能改
logger #日志配置列表
#修改日志级别
logger -n 名字 -l info/debug.... #名字注意大小写
jvm #jvm信息 包括内存信息和gc次数和表计算法次数时间等
classloader #类加载树
# 类方法查找
sc com.demo.* .xx.xx.* #找类找方法
sm -d com.demo.* .xx.xx.* 方法名 #打印 方法的详细信息,包括名字,注解,入参,出参classloader hashcode
classloader -t#类加载树 对于ResourceNotFoundException比较有用
表达式变量
下面方法会用到的
变量名 | 变量解释 |
---|---|
loader | 本次调用类所在的 ClassLoader |
clazz | 本次调用类的 Class 引用 |
method | 本次调用方法反射引用 |
target | 本次调用类的实例 |
params | 本次调用参数列表,这是一个数组,如果方法是无参方法则为空数组 |
returnObj | 本次调用返回的对象。当且仅当 isReturn==true 成立时候有效,表明方法调用是以正常返回的方式结束。如果当前方法无返回值 void,则值为 null |
throwExp | 本次调用抛出的异常。当且仅当 isThrow==true 成立时有效,表明方法调用是以抛出异常的方式结束。 |
isBefore | 辅助判断标记,当前的通知节点有可能是在方法一开始就通知,此时 isBeforetrue 成立,同时 isThrowfalse 和 isReturn==false,因为在方法刚开始时,还无法确定方法调用将会如何结束。 |
isThrow | 辅助判断标记,当前的方法调用以抛异常的形式结束。 |
isReturn | 辅助判断标记,当前的方法调用以正常返回的形式结束。 |
链路~观察(debug)
#-n 必须加上,不然线上死了你就哭去吧
#方法的执行链路,默认不显示jdk的函数,设置这个可以显示jdk的函数 --skipJDKMethod false。
trace class method -n 1
trace --skipJDKMethod false class method
#该方法被谁调用,,调用链路
stack class method -n
#根据条件过滤
stack com.liangwei.demo.controller.ArthasDemoController getMap 'params[0]>1' -n 2
#快照功能
#记录这个方法n次调用的记录
tt 类 方法 -n 请求数
#根据index重新执行一次 新的线程,线程变量(ThreadLocal)会丢失哦
tt --play -i
#记录 RequestMappingHandlerAdapter invokeHandlerMethod 3次
tt -t org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter invokeHandlerMethod -n 3
#获取上下文并获取实体bean执行getString方法,1003是index序号
tt -i 1003 -w'target.getApplicationContext().getBean("arthasDemoServiceImpl").getString("11111111111111111111","22222222222222222222222")'
#ognlཔ表达式,获取上下文静态变量也可以执行
ognl #context=@com.liangwei.demo.context.ApplicationContextUtil@applicationContext,#context.getBean("arthasDemoServiceImpl").getString("123333333333","4444444444444444444444444444")' -x 2
#debug -n加上哦
#观察getString 参数 1,2 和返回值 -x是类型的深度
watch com.liangwei.demo.service.impl.ArthasDemoServiceImpl getString {params[0],params[1],returnObj} -x 2 -n 1
@Component
public class ApplicationContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext1) throws BeansException {
applicationContext = applicationContext1;
}
public static <T> T getBean(Class<T> clazz) {
return applicationContext.getBean(clazz);
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
}
热部署
#反编译,并下载源码
jad --source-only com.liangwei.demo.service.impl.ArthasDemoServiceImpl > /tmp/ArthasDemoServiceImpl.java
#另外个窗口修改源码
gedit /tmp/ArthasDemoServiceImpl.java
#查找类的classloaderhashcode
sc -d com.liangwei.demo.service.impl.ArthasDemoServiceImpl |grep classLoaderHash
#编译
mc -c 18b4aac2 /tmp/ArthasDemoServiceImpl.java -d /tmp/class
#redefine
#注意:不允许新增加field/method ,
#正在执行的函数
#和jad/watch/trace/monitor/tt冲突会被重置
#lamber表达式(x->{xx})也是方法哦
#jdk版本要一致哦
redefine xxx.class