一、arthas简述
Arthas 是阿里开源的Java诊断工具。安装在系统所在服务器,有着强大的能力,是一个开发运维神器。主要功能
在线热替换代码/代码增强
全局视角的性能分析
查看方法执行情况,帮助跟踪偶现的bug
支持JDK6
二、官方资料
官方文档的介绍非常详尽:https://arthas.aliyun.com/doc/
使用官方的在线交互式教程来熟悉操作:https://arthas.aliyun.com/doc/arthas-tutorials.html?language=cn
三、idea安装插件arthas idea
使用(选择方法或者静态变量,右键,在弹出框中选择arthas command,然后再选择对应的命令,就会copy生成好对应的命令)
四、命令使用
相关命令使用可以看官方文档,下面只是简单说明下常用命令
version:查看当前Arthas版本
help:arthas命令行帮助
dashboard:系统监控台信息
classloader:显示所有类加载信息
sysprop:打印所有的System Properties信息
指定单个key
sysprop user.dir
通过grep过滤
sysprop | grep user
设置新的value
sysprop testKey testValue
sysenv: 命令可以获取到环境变量。和sysprop命令类似。
jvm :打印出JVM的各种详细信息
heapdump:似jmap命令的heapdump功能
dump到临时文件
heapdump
dump到指定文件
heapdump ./dump.hprof
只dump live对象
heapdump--live ./dump.hprof
thread: 查看线程相关信息
查看所有线程信息
thread
查看线程ID 2的栈:
thread 2
查看CPU使用率top n线程的栈
thread -n 3
查看5秒内的CPU使用率top n线程栈
thread -n 3 -i 5000
查找线程是否有阻塞
thread -b
jad: 反编译类
反编译想要的类,保存为文本文件
jad --source-only com.example.demo.arthas.user.UserController > /tmp/UserController.java
sm: 命令则是查找类的具体函数
sm -d java.math.RoundingMode
sc: 查找jvm加载的类
找到被修改类的classloader的哈希值
sc -d *UserController | grepclassLoaderHash
mc: 编译文件
通过mc(Memory Compiler)来编译修改好的.java文件,使用-c来指定classLoader,使用-d指定输出目录
mc -c1be6f5ff /tmp/UserController.java -d /tmp
redefine: 热加载编译好的文件
redefine/tmp/com/example/demo/arthas/user/UserController.class
monitor:方法执行监控
每5秒统计一次
monitor -c 5 class method
watch:方法执行数据观测
如果是列表,则会过滤列表中长度大于10的字符串
watch class method "{params,returnObj,throwExp}" "params[0].length() > 10" -x 1
按条件过滤后展示指定属性
watch class method "{params[0].{? #this.name.length() > 5}.{age}}" -n 1 -x 1
找到第一个符合条件的数据,用^
watch class method "{params[0].{^ #this.name.length() > 5}.{age}}" -n 1 -x 1
找到最后一个符合条件的数据,用$
watch class method "{params[0].{$ #this.name.length() > 5}.{age}}" -n 1 -x 1
trace:方法内部调用路径,并输出方法路径上的每个节点上耗时
追踪方法的内部调用
trace class method -n 5 --skipJDKMethod false
过滤大于200ms的调用链,只输出一次
trace class method '#cost>200' -n 1
stack:输出当前方法被调用的调用路径
tt:方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测
使用tt命令从调用记录里获取到spring context
tt -i 1000 -w 'target.getApplicationContext()'
获取spring bean,并调用函数
tt -i 1000 -w ‘target.getApplicationContext().getBean(“helloWorldService”).getHelloMessage()’
ognl:动态执行代码
调用static函数
ognl '@java.lang.System@out.println("hello ognl")'
获取静态类的静态字段(获取UserController类里的logger字段)
ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader @com.example.demo.arthas.user.UserController@logger
通过-x参数控制返回值的展开层数。比如:
ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader -x 2 @com.example.demo.arthas.user.UserController@logger
执行多行表达式,赋值给临时变量,返回一个List
ognl '#value1=@System@getProperty("java.home"), #value2=@System@getProperty("java.runtime.name"), {#value1, #value2}'
单独设置UserController的logger level
ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader '@com.example.demo.arthas.user.UserController@logger.setLevel(@ch.qos.logback.classic.Level@DEBUG)'
修改logback的全局logger level
ognl --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader '@org.slf4j.LoggerFactory@getLogger("root").setLevel(@ch.qos.logback.classic.Level@DEBUG)'
OGNL特殊用法请参考:https://github.com/alibaba/arthas/issues/71
五、例子
排查HTTP请求返回401
401通常是被权限管理的Filter拦截了,那么到底是哪个Filter处理了这个请求,返回了401?
跟踪所有的Filter函数
trace javax.servlet.Filter *
可以在调用树的最深层,找到AdminFilterConfig$AdminFilter返回了401
通过stack获取调用栈
上面是通过trace命令来获取信息,从结果里,我们可以知道通过stack跟踪HttpServletResponse:sendError(),同样可以知道是哪个Filter返回了401
stack javax.servlet.http.HttpServletResponse sendError 'params[0]==401'