阿里开源诊断工具-Arthas的使用。
参考:
https://segmentfault.com/a/1190000019413202
https://alibaba.github.io/arthas/install-detail.html
下载
curl -sk https://arthas.gitee.io/arthas-boot.jar -o ~/.arthas-boot.jar && echo "alias as.sh='java -jar ~/.arthas-boot.jar --repo-mirror aliyun --use-http'" >> ~/.bashrc && source ~/.bashrc
方式一:
# 安装
curl -O https://arthas.gitee.io/arthas-boot.jar
# 启动arthas,会进入命令行交互状态
java -jar arthas-boot.jar
# 退出
quit
# 也可以指定IP
java -jar arthas-boot.jar --target-ip 0.0.0.0
方式二:
# 安装
curl -L https://alibaba.github.io/arthas/install.sh | sh
# 启动arthas,会进入命令行交互状态
./as.sh
# 查看arthas命令手册
./as.sh -h
基础使用
选择要诊断的程序,进入命令行:
dashbord
通过dashboard
命令可以实时查看应用监控数据
线程
输入thread命令,会显示所有线程的状态信息
输入thread -b 会显示当前处于BLOCKED状态的线程,可以排查线程锁的问题
查看具体线程:thread id
输入thread -n 3会显示当前最忙的3个线程,可以用来排查线程CPU消耗
JVM
输入jvm命令,查看jvm详细的性能数据
监视函数参数和返回值
watch com.alvin.controller.PageController getPage "{params,returnObj}" -x 2
监视函数调用时间
trace可以监视每一行代码执行的时间
trace com.alvin.controller.PageController getPage
idea插件
arthas idea https://plugins.jetbrains.com/plugin/13581-arthas-idea
自动生成代码监视语句。
常用功能
配置静态applicationContext
可以获取spring变量、调用spring方法。
1、放置application类。
ApplicationContextProvider.java
2、配置
3、复制命令,并执行
反编译
效果
获取spring对象
我们可以直接获取spring对象的属性,还能手动调用里面的方法。
源码
获取类加载器
静态属性
ognl -x 3 '@com.alvin.arthas.ArthasUtil@a' -c 20ad9418
静态方法
ognl -x 3 '@com.alvin.arthas.ArthasUtil@test("1")' -c 20ad9418
普通属性
ognl -x 3 '#springContext=@com.alvin.arthas.ApplicationContextProvider@context,#springContext.getBean("arthasUtil").b' -c 20ad9418
普通方法
ognl -x 3 '#springContext=@com.alvin.arthas.ApplicationContextProvider@context,#springContext.getBean("arthasUtil").test2("2")' -c 20ad9418
获取spring环境变量
x
ognl -x 3 '#springContext=@com.alvin.common.ApplicationContextProvider@context,#springContext.getEnvironment().getProperty("server.port")' -c 439f5b3d
统计函数执行效率
monitor
# 每十秒统计一次
monitor com.alvin.controller.LightEventPublisher publish -c 10
监视方法的入参和出参
watch
监视方法的内部行执行时间
trace
其他
tt 函数隧道
记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测
通过tt也可以获取spring容器。
获取上次执行类,-n 统计次数
tt -t org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter invokeHandlerMethod -n 1
通过target获取spring容器
tt -i 1000 -w 'target.getApplicationContext().getBean("arthasUtil").b' -c 20ad9418
查看有什么类
search class
查看有什么方法
search method
获取代理类(controller service)
1、工具类
package com.alvin.util;
import org.springframework.aop.framework.AdvisedSupport;
import org.springframework.aop.framework.AopProxy;
import org.springframework.aop.support.AopUtils;
import java.lang.reflect.Field;
public class AopTargetUtils {
/**
* 获取 目标对象
* @param proxy 代理对象
* @return
* @throws Exception
*/
public static Object getTarget(Object proxy) throws Exception {
if(!AopUtils.isAopProxy(proxy)) {
return proxy; //不是代理对象
}
if(AopUtils.isJdkDynamicProxy(proxy)) {
return getJdkDynamicProxyTargetObject(proxy);
} else { //cglib
return getCglibProxyTargetObject(proxy);
}
}
private static Object getCglibProxyTargetObject(Object proxy) throws Exception {
Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0");
h.setAccessible(true);
Object dynamicAdvisedInterceptor = h.get(proxy);
Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
advised.setAccessible(true);
Object target = ((AdvisedSupport)advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();
return target;
}
private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception {
Field h = proxy.getClass().getSuperclass().getDeclaredField("h");
h.setAccessible(true);
AopProxy aopProxy = (AopProxy) h.get(proxy);
Field advised = aopProxy.getClass().getDeclaredField("advised");
advised.setAccessible(true);
Object target = ((AdvisedSupport)advised.get(aopProxy)).getTargetSource().getTarget();
return target;
}
}
2、命令
ognl -x 3 '#springContext=@com.alvin.arthas.ApplicationContextProvider@context,#proxyBean=#springContext.getBean("lightEventPublisher"),@com.alvin.util.AopTargetUtils@getTarget(#proxyBean).a' -c 20ad9418
查看线程死锁
代码
查看死锁: