欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Arthas教程

程序员文章站 2022-05-21 19:59:12
...

Arthas 介绍

什么是Arthas,它能为我们做什么

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

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

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

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

Arthas相关地址

基础教程

启动arthas-boot

下载arthas-boot.jar,再用java -jar命令启动

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

arthas-bootArthas的启动程序,它启动后,会列出所有的Java进程。

Arthas教程

选择需要诊断的目标进程,再Enter/回车,Attach成功之后,会打印Arthas LOGO。

Arthas教程

输入 help 获取到更多命令的帮助信息。输入对应命令+ --help 查看该命令帮助信息。如dashboard --help

Arthas教程

常用命令

Dashboard

dashboard 命令可以查看当前系统的实时数据面板。

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

Thread

thread 命令会打印线程的栈。

Arthas支持管道,可以用 thread 1 | grep main 查找到main class

可以看到main classdemo.MathGame

Arthas教程

Sc

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

sc -d *MathGame

Jad

可以通过 jad 命令来反编译代码:

jad demo.MathGame

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

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

Watch

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

watch demo.MathGame primeFactors returnObj

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

Arthas教程

Exit/Shutdown

  • 退出Arthas

    exit 或者 quit 命令可以退出Arthas。

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

  • 彻底退出Arthas

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

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

进阶教程

常用命令

查看JVM信息

sysprop

  • 可以通过sysprop打印所有的System Properties信息

    sysprop
    
  • 也可以指定单个key:

    sysprop java.version
    
  • 也可以通过grep来过滤:

    sysprop | grep user
    
  • 可以设置新的value:sysprop key value 例如:

    sysprop testKey testValue
    

Arthas教程

sysenv

可以sysenv命令获取到环境变量。和sysprop命令类似。

sysenv

Arthas教程

jvm

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

jvm

Arthas教程

查看已加载的类

sc

sc 命令可以查找到所有JVM已经加载到的类。

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

sc javax.servlet.Filter

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

sc -d javax.servlet.Filter

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

sc *StringUtils

sm

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

sm java.math.RoundingMode

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

sm -d java.math.RoundingMode

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

sm java.math.RoundingMode <init>

Arthas教程

使用技巧

自动补全

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

比如输入 sysprop java. 之后,再输入Tab,会补全出对应的key:

Arthas教程

readline的快捷键支持

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

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

Arthas教程

历史命令的补全

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

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

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

Arthas教程

pipeline

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

sysprop | grep java
sysprop | wc -l

Ognl

在Arthas里,有一个单独的ognl命令,可以动态执行代码。

  • 调用static函数

    ognl '@aaa@qq.com("hello ognl")'
    
  • 获取静态类的静态字段

    获取UserController类里的logger字段

    ognl -c 1be6f5c3 @aaa@qq.com
    

    还可以通过-x参数控制返回值的展开层数。

    ognl -c 1be6f5c3 -x 2 @aaa@qq.com
    
  • 执行多行表达式,赋值给临时变量,返回一个List

    ognl '#aaa@qq.com@getProperty("java.home"), #aaa@qq.com@getProperty("java.runtime.name"), {#value1, #value2}'
    

    Arthas教程

更多

在Arthas里ognl表达式是很重要的功能,在很多命令里都可以使用ognl表达式。

一些更复杂的用法,可以参考:

使用案例

排查函数调用异常

现象

目前,访问 http://localhost/user/0 ,会返回500异常

curl http://localhost/user/0

Arthas教程

但请求的具体参数,异常栈是什么呢?

查看UserController的 参数/异常

在Arthas里执行

watch com.example.demo.arthas.user.UserController * '{params, throwExp}'
  1. 第一个参数是类名,支持通配
  2. 第二个参数是函数名,支持通配

访问 curl http://localhost/user/0 ,watch命令会打印调用的参数和异常

Arthas教程

​ 可以看到实际抛出的异常是IllegalArgumentException

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

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

Arthas教程

返回值表达式

在上面的例子里,第三个参数是返回值表达式,它实际上是一个ognl表达式,它支持一些内置对象:

  • loader
  • clazz
  • method
  • target
  • params
  • returnObj
  • throwExp
  • isBefore
  • isThrow
  • isReturn

你可以利用这些内置对象来组成不同的表达式。比如返回一个数组

watch com.example.demo.arthas.user.UserController * '{params[0], target, returnObj}'

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

条件表达式

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

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

当访问 http://localhost/user/1时,watch命令没有输出

当访问 http://localhost/user/111时,watch会打印出结果

Arthas教程

当异常时捕获

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

按照耗时进行过滤

watch命令支持按请求耗时进行过滤

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

热更新代码

通过jad/mc/redefine 命令实现动态更新代码的功能

现象

目前,访问 http://localhost/user/0 ,会返回500异常

下面通过热更新代码,修改这个逻辑。

jad反编译UserController

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

jad反编译的结果保存在 /tmp/UserController.java文件里了,然后用vim来编辑/tmp/UserController.java

vim /tmp/UserController.java

我们将代码修改为如下

Arthas教程

sc查找加载UserController的ClassLoader

sc -d *UserController | grep classLoaderHash

可以发现是 spring boot aaa@qq.com 加载的。

Arthas教程

mc编译UserController

保存好/tmp/UserController.java之后,使用mc(Memory Compiler)命令来编译,并且通过-c参数指定ClassLoader

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

Arthas教程

redefine重新加载新编译好class文件

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

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

Arthas教程

查看修改后的结果

redefine成功之后,再次访问 http://localhost/user/0 ,结果如下:

Arthas教程

动态更新应用日志级别

查找UserController的ClassLoader

sc -d com.example.demo.arthas.user.UserController | grep classLoaderHash

Arthas教程

用ognl获取logger

ognl -c 1be6f5c3 '@aaa@qq.com'

Arthas教程

可以知道aaa@qq.com实际使用的是logback。可以看到level=null,则说明实际最终的level是从root logger里来的。

单独设置UserController的logger level

ognl -c 1be6f5c3 '@aaa@qq.comsetLevel(@aaa@qq.com)'

再次获取aaa@qq.com,可以发现已经是DEBUG

Arthas教程

修改logback的全局logger level

通过获取root logger,可以修改全局的logger level

ognl -c 1be6f5c3 '@aaa@qq.com("root").setLevel(@aaa@qq.com)'

排查logger冲突问题

确认应用使用的logger系统

UserController为例,它使用的是slf4j api,但实际使用到的logger系统是logback

ognl -c 1be6f5c3 '@aaa@qq.com'

获取logback实际加载的配置文件

ognl -c 1be6f5c3 '#aaa@qq.com@getLogger("root").loggerContext.objectMap, #map1.get("CONFIGURATION_WATCH_LIST")'

Arthas教程

查找可能存在的logger配置文件

classloader -c 1be6f5c3 -r logback-spring.xml

Arthas教程

可以知道加载的配置的具体来源,尝试加载容易冲突的文件

Arthas教程

获取Spring Context

案例步骤:获取spring context -> 获取bean -> 调用函数

获取spring context

使用tt命令获取到spring context

tt即 TimeTunnel,它可以记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测。参考文档:https://alibaba.github.io/arthas/tt.html

tt -t org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter invokeHandlerMethod

访问

http://localhost/user/1

http://localhost/user/0

http://localhost/user/0

可以看到tt命令捕获到了如下请求

Arthas教程

从调用记录里获取到spring context

使用tt命令从调用记录里获取到spring context

输入 Q 或者 Ctrl + C 退出上面的 tt -t命令。

输入如下命令查看index为1000的请求的信息

tt -i 1000 -w 'target.getApplicationContext()'

Arthas教程

获取spring bean,并调用函数

tt -i 1000 -w 'target.getApplicationContext().getBean("helloWorldService").getHelloMessage()'

Arthas教程


Arthas教程

相关标签: Arthas