Arthas学习

导读:本篇文章讲解 Arthas学习,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

使用场景

  1. 这个类从哪个jar包加载的?为什么会报各种类相关的Exception?
  2. 我改的代码为什么没有执行到?每提交么?提交的分支不对么?
  3. 遇到问题无法在线上debug,难道只能通过添加日志然后重新发布么?
  4. 线上遇到某个用户的数据处理有问题,但线上同样无法debug,线下无法重现!
  5. 是否有一个全局视角来查看系统的运行情况?
  6. 有什么办法可以监控到JVM的实时运行状态?
  7. 怎么快速定位应用的热点,生成火焰图?

安装

推荐使用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
    其他安装方式自行查找

基本命令

绑定进程

  1. 启动Demo
    curl -O https://alibaba.github.io/arthas/arthas-demo.jar
    java -jar arthas-demo.jar
    arthas-demo是一个简单的程序,每隔一秒生成一个随机数,再执行质因数分解,并打印出分解结果。

  2. 启动arthas
    在命令行下面执行(使用和目标进程一致的用户启动,否则attach失败):
    java -jar arthas-boot.jar

  3. 执行该程序的用户需要和目标进程具有相同的权限。比如以admin用户来执行:
    sudo su admin && java -jar arthas-boot.jar 或者 sudo -u admin -EH java -jar arthas-boot.jar。

  4. 如果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

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!