菜单开关

周梦康 发表于 2021-09-25 66 次浏览 标签 : arthas

Arthas 介绍

Arthashttps://arthas.aliyun.com/doc/)是Alibaba开源的Java诊断工具。

当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决:

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

安装方式

curl -L https://arthas.aliyun.com/install.sh | sh

上述命令会下载启动脚本文件 as.sh 到当前目录,直接在shell下面执行./as.sh,就会进入交互界面。

我用的最高频的操作的就是它的tracewatch功能,

  • trace https://arthas.aliyun.com/doc/trace.html 可以看到完整的调用链和各个耗时,比如下面查看demo.MathGamerun方法,耗时超过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()
  • watch https://arthas.aliyun.com/doc/watch.html 观察到指定方法的调用情况。能观察到的范围为:返回值抛出异常入参,比如下面,监控demo.MathGameprimeFactors方法,-x 2表示输出结果的属性遍历深度
$ watch demo.MathGame primeFactors -x 2
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 32 ms, listenerId: 5
method=demo.MathGame.primeFactors location=AtExit
ts=2021-08-31 15:22:58; [cost=1.020982ms] result=@ArrayList[
    @Object[][ // 参数
        @Integer[1], 
    ],
    @MathGame[ // 对象
        random=@Random[java.util.Random@31cefde0],
        illegalArgumentCount=@Integer[44],
    ],
    @ArrayList[ // 返回值
        @Integer[2],
        @Integer[2],
        @Integer[26947],
    ],
]

快捷插件

因为手册上的命令、表达式,还是很有难度的,比较容易忘记,很多深层次好用的功能不容被挖掘,所有人搞了这个插件,良心大作啊,文档齐全,长时间更新,https://www.yuque.com/arthas-idea-plugin/help/pe6i45

比如,常用的 watch命令,只用在ide里,点点点就能生成命令,到服务器上粘贴运行即可,非常方便,强烈推荐

  • trace https://arthas.aliyun.com/doc/trace.html 可以看到完整的调用链和各个耗时,比如下面查看demo.MathGamerun方法,耗时超过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()
  • watch https://arthas.aliyun.com/doc/watch.html 观察到指定方法的调用情况。能观察到的范围为:返回值抛出异常入参,比如下面,监控demo.MathGameprimeFactors方法,-x 2表示输出结果的属性遍历深度
$ watch demo.MathGame primeFactors -x 2
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 32 ms, listenerId: 5
method=demo.MathGame.primeFactors location=AtExit
ts=2021-08-31 15:22:58; [cost=1.020982ms] result=@ArrayList[
    @Object[][ // 参数
        @Integer[1], 
    ],
    @MathGame[ // 对象
        random=@Random[java.util.Random@31cefde0],
        illegalArgumentCount=@Integer[44],
    ],
    @ArrayList[ // 返回值
        @Integer[2],
        @Integer[2],
        @Integer[26947],
    ],
]

arthas 还有很多更高级的用法,但是一些命令容易忘记,表达式又有一定的语法门槛也难记忆,好消息是在插件里面都有封装,我们只需要点点点就能快速的生成命令,便于在服务器上粘贴执行了,强烈推荐
https://www.yuque.com/arthas-idea-plugin/help/pe6i45

热部署

经常会遇到因为某一小块代码逻辑写得不对,导致需要重续部署的情况,这样又是一杯咖啡的时间过去了,想不加班都难啊,所以 arthas 提供了热部署功能 https://arthas.aliyun.com/doc/redefine.html 单独编译某一个类文件,然后将其执行热部署

jad --source-only com.example.demo.arthas.user.UserController > /tmp/UserController.java
mc /tmp/UserController.java -d /tmp
redefine /tmp/com/example/demo/arthas/user/UserController.class

但是实际情况会复杂一些,因为我们需要把本地编译好的文件上传到服务器上,非常的麻烦,上面说的插件又帮我解决了这一问题, https://www.yuque.com/arthas-idea-plugin/help/pwxhb4 支持剪切板 base64 的方式复制粘贴,但是更推荐配置一个阿里云 oss 作为中转跳板上传和下载。

运维监控

有时候一些异常只会抽风式偶尔出现,想抓现行,比较困难,所以需要一个监控。比如像找到 cpu 达到80%的时候的最忙碌的线程的 top n,可以使用 arthas 的 thread -n 10 功能,但是 arthas 是交互式的,需要我们补充点管道的知识,也就是下面的mknod arthas_input p

#!/bin/bash

ctime=$(date "+%H-%M-%S")
cpu_percent=`top -n 1 | grep Cpu| awk -F " " '{print int($2)}'`

if [ ${cpu_percent} > 80 ] ; then
  echo "${ctime}开始采集最占 cpu 的线程"
  mknod arthas_input p
  exec 8<> arthas_input
  ./as.sh <&8 &
  echo -e "1\n" >> arthas_input

  echo "thread -n 10 > $(pwd)/arthas.${cpu_percent}.${ctime}.result" >> arthas_input
  echo "quit" >> arthas_input
  rm -f arthas_input
  sleep 2s
fi

这样即使半夜或者在公交车上,或者在打游戏,都不慌了,报警过后直接看日志就行了。当然是 nohup 的方式启动该脚本

同理之前还遇到过在偶发的线上某个接口特别慢,超时的错误提醒,所以呢,我也在线上直接使用了这个脚本,值抓取那些耗时超过 2s 的请求日志

#!/bin/bash

ctime=$(date "+%H-%M-%S")

mknod arthas_input p
exec 8<> arthas_input
./as.sh <&8 &
echo -e "1\n" >> arthas_input

echo "trace xxxx getCourseDetail '#cost > 2000' >> $(pwd)/arthas.trace.log" >> arthas_input

最终根据日志也顺利定位解决了问题。

评论列表