阿里巴巴-Arthas诊断工具

Alibaba开源的Java诊断工具-Arthas

Posted by Hyuga on July 30, 2019

官方简介

Arthas(阿尔萨斯)是阿里巴巴开源的 Java 诊断工具

官方文档:https://alibaba.github.io/arthas

项目地址:https://gitee.com/arthas/arthas

Arthas

Arthas 是Alibaba开源的Java诊断工具,深受开发者喜爱。

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

  • 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
  • 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
  • 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
  • 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
  • 是否有一个全局视角来查看系统的运行状况?
  • 有什么办法可以监控到JVM的实时运行状态?

Arthas支持JDK 6+,支持Linux/Mac/Windows,采用命令行交互模式,同时提供丰富的 Tab 自动补全功能,进一步方便进行问题的定位和诊断。

在线教程(推荐)
三种安装方式

第一种

按官方推荐的快速开始方法!使用arthas-boot.jar,用jar包方式启动。

wget https://alibaba.github.io/arthas/arthas-boot.jar
java -jar arthas-boot.jar

这里遇到一点小问题,linux上没有安装wget,这个自行百度下,或者参考 Linux 常规指令技巧

如果下载速度比较慢,可以使用aliyun的镜像:java -jar arthas-boot.jar --repo-mirror aliyun --use-http

第二种

打开项目地址,找到最新的一个标签,拉取最新的一个可用包下载。

下载后解压可得arthas目录,里面有可运行文件 /arthas/bin/as.sh

https://gitee.com/arthas/arthas/repository/archive/arthas-all-3.1.1

第三种

这种也是相对最方便的一种:curl -L https://alibaba.github.io/arthas/install.sh | sh

官方是这样介绍的:Arthas 支持在 Linux/Unix/Mac 等平台上一键安装,请复制以下内容,并粘贴到命令行中,敲 回车 执行即可。

上述命令会下载启动脚本文件 as.sh 到当前目录,你可以放在任何地方或将其加入到 $PATH 中。

直接在shell下面执行./as.sh,就会进入交互界面。

也可以执行./as.sh -h来获取更多参数信息。

指定端口启动

端口冲突时,通过以下命令启动:

java -jar /data/www/hyuga/arthas-boot.jar --telnet-port 9998 --http-port -1

Exit/Shutdown 退出Arthas

exit 或者 quit 命令可以退出Arthas

重连Arthas

退出Arthas之后,还可以再次用 java -jar arthas-boot.jar 来连接。

彻底退出Arthas

exit/quit命令只是退出当前sessionarthas server还在目标进程中运行。

想完全退出Arthas,可以执行 shutdown 命令。

使用

Dashboard 系统实时数据面板

输入Q + 回车 或者 Ctrl + C 可以退出dashboard命令。

sysprop

sysprop 可以打印所有的System Properties信息。

sysprop java.version 也可以指定单个key

sysprop | grep user 也可以通过grep来过滤

sysprop testKey testValue 可以设置新的value[慎用]

sysenv

sysenv 命令可以获取到环境变量。和sysprop命令类似。相对sysprop信息简化不少。

jvm

jvm 命令会打印出JVM的各种详细信息。

help

Arthas里每一个命令都有详细的帮助信息。可以用-h来查看。帮助信息里有EXAMPLES和WIKI链接。

eg: sysprop -h

自动补全

Arthas支持丰富的自动补全功能,在使用有疑惑时,可以输入Tab来获取更多信息。

readline的快捷键支持

Arthas支持常见的命令行快捷键,比如Ctrl + A跳转行首,Ctrl + E跳转行尾。

更多的快捷键可以用执行keymap命令查看。

历史命令的补全

如果想再执行之前的命令,可以在输入一半时,按Up/↑ 或者 Ddown/↓,来匹配到之前的命令。

比如之前执行过sysprop java.version,那么在输入sysprop ja之后,可以输入Up/↑,就会自动补全为sysprop java.version。

如果想查看所有的历史命令,也可以通过history命令查看到。

pipeline

Arthas支持在pipeline(管道)之后,执行一些简单的命令,比如:

sysprop | grep java

sysprop | wc -l

Sc 命令

可以通过 sc 命令来查找JVM里已加载的类!

如果搜索的是接口,还会搜索所有的实现类。比如查看所有的Filter实现类:

sc javax.servlet.Filter

通过-d参数,可以打印出类加载的具体信息,很方便查找类加载问题。

sc -d javax.servlet.Filter

sc支持通配,比如搜索所有的MathGame:

sc -d *MathGame

根据包名+类名查看某个已被JVM加载的类,也可以通过星号进行模糊查询。

sc查找加载UserController的ClassLoader

sc -d *UserController | grep classLoaderHash

$ sc -d *UserController | grep classLoaderHash
 classLoaderHash   1be6f5c3

可以发现是 spring boot LaunchedURLClassLoader@1be6f5c3 加载的。

mc

使用mc(Memory Compiler)命令可以编译java文件,并且通过-c参数指定ClassLoader:

mc -c 1be6f5c3 /tmp/UserController.java -d /tmp

1be6f5c3是通过sc命令查找出来的加载UserController.java类的类加载器的hashCode

$ mc -c 1be6f5c3 /tmp/UserController.java -d /tmp
Memory compiler output:
/tmp/com/example/demo/arthas/user/UserController.class
Affect(row-cnt:1) cost in 346 ms

通过mc命令指定类加载器重新编译java类,编译好的class文件存储在包名同路径下

redefine

使用redefine命令重新加载新编译好的UserController.class:

redefine /tmp/com/example/demo/arthas/user/UserController.class

$ redefine /tmp/com/example/demo/arthas/user/UserController.class
redefine success, size: 1

通过jad反编译保存源码,修改源码,sc查找对应类加载器,mc指定类加载器重新编译java文件,redefine重新加载编译好的class文件

Sm 命令

sm命令则是查找类的具体函数。比如:

sm java.math.RoundingMode

通过-d参数可以打印函数的具体属性:

sm -d java.math.RoundingMode

也可以查找特定的函数,比如查找构造函数:

sm java.math.RoundingMode <init>

demo

sm -d com.syzl.web.mgr.controller.security.system.CityCompanySettingController pageCityCompany

非常直观的打印出pageCityCompany方法的各种详细信息,做线上排查非常有帮助。

thread 查看线程

thread 打印所有应用所有线程信息

thread 16 查看线程ID 16的栈

thread -n 3 查看CPU使用率top n线程的栈

thread -n 3 -i 5000 查看5秒内的CPU使用率top n线程栈

thread -b 查找线程是否有阻塞

获取 Main Class

thread 1 | grep 'main('

$ thread 1 | grep 'main('
    at demo.MathGame.main(MathGame.java:17)
Jad 反编译

非常实用的一个功能!!!可以通过 jad 命令来反编译代码:

jad com.example.demo.arthas.user.UserController

通过–source-only参数可以只打印出在反编译的源代码:

jad --source-only com.example.demo.arthas.user.UserController

反编译内容保存到文件:

jad --source-only com.example.demo.arthas.user.UserController > /tmp/UserController.java

jad反编译的结果保存在 /tmp/UserController.java文件里了。

很强的功能,直接根据包名+类名,反编译出线上某个已被jvm加载的类的源码信息。

Watch 命令

通过watch命令可以查看函数的参数/返回值/异常信息。

watch com.example.demo.arthas.user.UserController * '{params, returnObj, throwExp}'

  • 第一个参数是类名,支持通配
  • 第二个参数是函数名,支持通配
  • 第三个参数是返回值表达式,它实际上是一个ognl表达式,它支持一些内置对象:
    • loader clazz method target params returnObj throwExp isBefore isThrow isReturn

如果想把获取到的结果展开,可以用-x参数:

watch com.example.demo.arthas.user.UserController * '{params, returnObj, throwExp}' -x 2

更多参考: https://alibaba.github.io/arthas/advice-class.html

输入 Q 或者 Ctrl+C 退出watch命令。

demo

watch com.syzl.web.mgr.controller.security.system.CityCompanySettingController pageCityCompany returnObj

很强大的功能,根据包名+类名+方法名,可以打印出接口实时调用所返回的数据,并且打印出该接口调用时间和调用响应总时长。

条件表达式

watch命令支持在第4个参数里写条件表达式,比如:

watch com.example.demo.arthas.user.UserController * returnObj 'params[0] > 100'

当访问 https://2886795319-80-elsy02.environments.katacoda.com/user/1 时,watch命令没有输出

当访问 https://2886795319-80-elsy02.environments.katacoda.com/user/101 时,watch会打印出结果。

当异常时捕获

watch命令支持-e选项,表示只捕获抛出异常时的请求:

watch com.example.demo.arthas.user.UserController * "{params[0],throwExp}" -e

or

watch com.example.demo.arthas.user.UserController * "{params[0],throwExp}" -e -x 2 打印具体异常信息

按照耗时进行过滤

watch命令支持按请求耗时进行过滤,比如:

watch com.example.demo.arthas.user.UserController * '{params, returnObj}' '#cost>200'

trace

跟踪所有的Filter函数

trace javax.servlet.Filter *

跟踪所有的Servlet函数

trace javax.servlet.Servlet * > /tmp/servlet.txt

classloader

列出所有ClassLoader

classloader -l

查看ClassLoader树

classloader -t

列出ClassLoader里加载的所有类

classloader -a -c 65361d9a(类加载器hashCode)

列出ClassLoader的urls

classloader -c 1be6f5c3

加载指定ClassLoader里的资源文件

查找指定的资源文件: classloader -c 1be6f5c3 -r logback-spring.xml

尝试加载指定的类

比如用上面的spring LaunchedURLClassLoader 尝试加载 java.lang.String :

classloader -c 1be6f5c3 --load java.lang.String

进阶命令

基础命令

  • help——查看命令帮助信息
  • cat——打印文件内容,和linux里的cat命令类似
  • pwd——返回当前的工作目录,和linux命令类似
  • cls——清空当前屏幕区域
  • session——查看当前会话的信息
  • reset——重置增强类,将被 Arthas 增强过的类全部还原,Arthas 服务端关闭时会重置所有增强过的类
    • Arthas在 watch/trace 等命令时,实际上是修改了应用的字节码,插入增强的代码。显式执行 reset 命令,可以清除掉这些增强代码。
  • version——输出当前目标 Java 进程所加载的 Arthas 版本号
  • history——打印命令历史
  • quit——退出当前 Arthas 客户端,其他 Arthas 客户端不受影响
  • shutdown——关闭 Arthas 服务端,所有 Arthas 客户端全部退出
  • keymap——Arthas快捷键列表及自定义快捷键

JVM相关

  • dashboard——当前系统的实时数据面板
  • thread——查看当前 JVM 的线程堆栈信息
  • jvm——查看当前 JVM 的信息
  • sysprop——查看和修改JVM的系统属性
  • sysenv——查看JVM的环境变量
  • getstatic——查看类的静态属性
  • New! ognl——执行ognl表达式
  • New! mbean——查看 Mbean 的信息

class/classloader相关

  • sc——查看JVM已加载的类信息
  • sm——查看已加载类的方法信息
  • jad——反编译指定已加载类的源码
  • mc——内存编绎器,内存编绎.java文件为.class文件
  • redefine——加载外部的.class文件,redefine到JVM里
  • dump——dump 已加载类的 byte code 到特定目录
  • classloader——查看classloader的继承树,urls,类加载信息,使用classloader去getResource

monitor/watch/trace相关

请注意,这些命令,都通过字节码增强技术来实现的,会在指定类的方法中插入一些切面来实现数据统计和观测,因此在线上、预发使用时,请尽量明确需要观测的类、方法以及条件,诊断结束要执行 shutdown 或将增强过的类执行 reset 命令。

  • monitor——方法执行监控
  • watch——方法执行数据观测
  • trace——方法内部调用路径,并输出方法路径上的每个节点上耗时
  • stack——输出当前方法被调用的调用路径
  • tt——方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测

options

  • options——查看或设置Arthas全局开关

管道

Arthas支持使用管道对上述命令的结果进行进一步的处理,如sm java.lang.String * | grep 'index'

  • grep——搜索满足条件的结果
  • plaintext——将命令的结果去除ANSI颜色
  • wc——按行统计输出结果

后台异步任务

当线上出现偶发的问题,比如需要watch某个条件,而这个条件一天可能才会出现一次时,异步后台任务就派上用场了,详情请参考这里

使用 > 将结果重写向到日志文件,使用 & 指定命令是后台运行,session断开不影响任务执行(生命周期默认为1天)

  • jobs——列出所有job
  • kill——强制终止任务
  • fg——将暂停的任务拉到前台执行
  • bg——将暂停的任务放到后台执行

Web Console

通过websocket连接Arthas。