Arthas学习
使用场景
- 这个类从哪个jar包加载的?为什么会报各种类相关的Exception?
- 我改的代码为什么没有执行到?每提交么?提交的分支不对么?
- 遇到问题无法在线上debug,难道只能通过添加日志然后重新发布么?
- 线上遇到某个用户的数据处理有问题,但线上同样无法debug,线下无法重现!
- 是否有一个全局视角来查看系统的运行情况?
- 有什么办法可以监控到JVM的实时运行状态?
- 怎么快速定位应用的热点,生成火焰图?
安装
推荐使用arthas-boot,下载arthas-boot.jar,然后使用java -jar的方式启动:
curl -O https://alibaba.github.io/arthas/arthas-boot.jar
java -jar arthas-boot.jar
打印帮助信息
java -jar arthas-boot.jar -h
- 如果下载速度比较慢,可以使用aliyun的镜像:
java -jar arthas-boot.jar –repo-mirror aliyun –use-http - 如果从github下载有问题,可以使用gitee镜像
curl -O https://arthas.gitee.io/arthas-boot.jar
其他安装方式自行查找
基本命令
绑定进程
-
启动Demo
curl -O https://alibaba.github.io/arthas/arthas-demo.jar
java -jar arthas-demo.jar
arthas-demo是一个简单的程序,每隔一秒生成一个随机数,再执行质因数分解,并打印出分解结果。 -
启动arthas
在命令行下面执行(使用和目标进程一致的用户启动,否则attach失败):
java -jar arthas-boot.jar -
执行该程序的用户需要和目标进程具有相同的权限。比如以admin用户来执行:
sudo su admin && java -jar arthas-boot.jar 或者 sudo -u admin -EH java -jar arthas-boot.jar。 -
如果attach不上目标进程,可以查看~/logs/arthas/目录下的日志。
选择应用java进程
Demo进程是第一个,则输入1,回车。Arthas会attach到目标进程上,并输出日志:
绑定多个进程
默认的绑定端口是:3658
如果需要绑定多个进程,需要使用下面命令,修改绑定端口
java -jar arthas-boot.jar --telnet-port 9998 --http-port -1
查看dashboard
输入dashboard,会展示当前进程的信息,按ctrl+c可以中断arthas的执行。
thread命令
通过thread 命令来获取arthas-demo进程的Main Class
thread 1会打印线程ID 1的栈,通常是main函数的线程。
jad命令
示例1:通过jad来反编译main class
示例2:反编译任意类
jad com.study..service.impl.StudyServiceImpl
watch命令
通过watch命令来查询demo.MathGame#primeFactors函数的返回值
退出arthas
如果只是退出当前的连接,可以使用quit或者exit命令。Attach到目标上的arthas还会继续运行,端口会保持开发,下次连接时可以直接连上。
如果想完全退出arthas,可以执行stop命令。
命令详解
trace
方法内部调用路径,并输出方法路径上的每个节点耗时。
trace命令能主动搜索class-pattern / method-pattern对应的方法调用路径,渲染和统计整个调用链路上的所有性能开销和追踪调用链路。
参数说明
- class-pattern:类名表达式匹配
- method-pattern:方法名表达式匹配
- codition-express:条件表达式
- [E]:开启正则表达式匹配,默认为通配符匹配
- [n:]:命令执行次数
- #cost:方法执行耗时
很多时候我们只想看到某个方法的RT(返回时间)大于某个时间之后的trace结果,现在Arthas可以按照方法执行的耗时来进行过滤了,例如:
trace *StringUtils isBlank '#cost>100'
上面命令表示当执行时间超过100ms的时候,才会输出trace结果。
watch/stack/trace 这三个命令都支持 #cost。
注意事项
trace能方便的帮助定位和发现因RT高而导致的性能问题缺陷,但其每次只能跟踪一级方法的调用链路。
3.3.0版本后,可以使用动态Trace功能,不断增加新的匹配类,参考下面的示例。
使用参考
trace函数
trace demo.MathGame run
按Q或者Ctrl+c退出。
$ trace demo.MathGame run
Press Q or Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 28 ms.
`---ts=2019-12-04 00:45:08;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@3d4eac69
`---[0.617465ms] demo.MathGame:run()
`---[0.078946ms] demo.MathGame:primeFactors() #24 [throws Exception]
`---ts=2019-12-04 00:45:09;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@3d4eac69
`---[1.276874ms] demo.MathGame:run()
`---[0.03752ms] demo.MathGame:primeFactors() #24 [throws Exception]
trace次数限制
如果方法调用的次数很多,那么可以用-n参数指定捕捉结果的次数。比如下面的例子里,捕捉到一次调用就退出命令。
trace demo.MathGame run -n 1
执行结果:
$ trace demo.MathGame run -n 1
Press Q or Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 20 ms.
`---ts=2019-12-04 00:45:53;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@3d4eac69
`---[0.549379ms] demo.MathGame:run()
+---[0.059839ms] demo.MathGame:primeFactors() #24
`---[0.232887ms] demo.MathGame:print() #25
Command execution times exceed limit: 1, so command will exit. You can set it with -n option.
包含jdk的函数
- –skipJDKMethod skip jdk method trace, default value true.
trace --skipJDKMethod false demo.MathGame run
默认情况下,trace不会包含jdk里的函数调用,如果希望trace jdk里的函数,需要显式设置–skipJDKMethod false。
据调用耗时过滤
trace demo.MathGame run '#cost > 10'
只会展示大于10ms的调用路径,有助于在排查问题的时候,只关注异常情况。
$ trace demo.MathGame run '#cost > 10'
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 41 ms.
`---ts=2018-12-04 01:12:02;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@3d4eac69
`---[12.033735ms] demo.MathGame:run()
+---[0.006783ms] java.util.Random:nextInt()
+---[11.852594ms] demo.MathGame:primeFactors()
`---[0.05447ms] demo.MathGame:print()
trace多个类或者多个函数
trace命令之后trace匹配到的函数里的子调用,并不会向下trace多层。因为trace是代价比较贵的,多层trace可能会导致最终trace的类和函数非常多。
可以用正则匹配路径上的多个类和函数,一定程度上达到多层trace的效果。
trace -E com.test.ClassA|org.test.ClassB method1|method2|method3
动态trace
3.3.0版本后支持。
打开终端1,trace demo.MathGame run函数,可以看到打印出 listenerId: 1:
[arthas@59161]$ trace demo.MathGame run
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 112 ms, listenerId: 1
`---ts=2020-07-09 16:48:11;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@3d4eac69
`---[1.389634ms] demo.MathGame:run()
`---[0.123934ms] demo.MathGame:primeFactors() #24 [throws Exception]
`---ts=2020-07-09 16:48:12;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@3d4eac69
`---[3.716391ms] demo.MathGame:run()
+---[3.182813ms] demo.MathGame:primeFactors() #24
`---[0.167786ms] demo.MathGame:print() #25
现在想要深入子函数primeFactors,可以打开一个新终端2,使用telnet localhost 3658连接上arthas,再trace primeFactors时,指定listenerId。
trace demo.MathGame primeFactors --listenerId 1
执行结果:
[arthas@59161]$ trace demo.MathGame primeFactors --listenerId 1
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 34 ms, listenerId: 1
这时终端2打印的结果,说明已经增强了一个函数:Affect(class count: 1 , method count: 1),但不再打印更多的结果。
再查看终端1,可以发现trace的结果增加了一层,打印了primeFactors函数里的内容:
`---ts=2020-07-09 16:49:29;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@3d4eac69
`---[0.492551ms] demo.MathGame:run()
`---[0.113929ms] demo.MathGame:primeFactors() #24 [throws Exception]
`---[0.061462ms] demo.MathGame:primeFactors()
`---[0.001018ms] throw:java.lang.IllegalArgumentException() #46
`---ts=2020-07-09 16:49:30;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@3d4eac69
`---[0.409446ms] demo.MathGame:run()
+---[0.232606ms] demo.MathGame:primeFactors() #24
| `---[0.1294ms] demo.MathGame:primeFactors()
`---[0.084025ms] demo.MathGame:print() #25
通过指定listenerId的方式动态trace,可以不断深入。另外 watch/tt/monitor等命令也支持类似的功能。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/100459.html