简介
Arthas 是Alibaba开源的Java诊断工具。
当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决:
这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
是否有一个全局视角来查看系统的运行状况?
有什么办法可以监控到JVM的实时运行状态?
================
以上是Arthas官方介绍。
Arthas提供了热更新线上代码功能,在线上部署Arthas是比较危险,会破坏线上代码的版本管理。所以,不建议在线上环境部署Arthas。但是可以在测试环境部署,用于测试环境的debug。其实各种IDE工具也提供了远程断点功能,使用IDE工具远程断点功能,需要满足以下条件:
以debug模式启动java虚拟机
保证本地代码和测试环境运行代码版本一致
本地开发环境与测试环境网络是通的
使用IDE进行断点并不能完全模拟测试环境,毕竟是部署的是两套系统,依赖包,环境可能会有不同。
安装
Arthas有多种安装方式,下面方式安装比较简单。
最新版本,点击下载:arthas
解压后,在文件夹里有arthas-boot.jar

直接用java -jar的方式启动:
java -jar arthas-boot.jar

Arthas启动会列出本地除了自己本身之外启动的jvm进程

以下就以MyPaasGatewayApplication为例,介绍Artthas部分功能使用。
使用
选择jvm进程列表对应的序号,连接到需要debug的jvm,这里选择编号为1的jvm

回车后进入所选jvm对应的命令行界面。
输入help看一下帮助。

可以看到arthas支持查询classloader,thread,jvm,dashboard,sysprop,sysenv等信息。
也支持使用jad反编译类,使用mc编译类,使用redefine重新加载类。
使用dashboard查看当前jvm概要信息。

可以看到当前jvm线程状况,memory使用状况的信息。
在调试代码的过程中,查看变量值的和更新字节码这两个功能用得多一些,下面以MyPaasGatewayApplication为例子演示一下如何使用arthas查看变量值和更新字节码。
查看变量值
在MyPaasGatewayApplication的实现中,有一个过滤器实现BuryPointFilter用于检查请求是否需要发送埋点信息,如果埋点信息开关开启,则发送埋点信息。代码如下:

假设测试环境没有开启debug lever log,或者懒得搜索日志,这里就可以用arthas的watch来观察shouldFilter方法的返回值。

watch后面接的参数为:
1.被观察对象的类名
2.被观察的方法
3.方法的返回值
可以看到输出
result=@Boolean[true]
表示shouldFilter返回的值是true.
更新字节码
手动禁掉BuryPointFilter,修改shouldFilter函数,总是返回false.
获取反编译代码

使用jad命令反编译类。
得到以下代码:

修改反编译出来的代码,改变shouldFilter的值,并打印log,log设置为warn级别,方便观察字节码修改结果。

查找加载BuryPointFilter的ClassLoader
生成的字节码要包含原来类加载器的信息,所以要找到BuryPointFilter是由jvm中哪个classLoader加载的。使用sc(search class)命令搜索classLoader信息.

-d 参数表示搜索详细信息(detail)
得到classLoader信息后,就可以生成带classLoader信息的字节码了。
生成代码修改后的字节码
使用mc(memory compiler)命令生成字节码

-c 参数指定classLoader
-d 参数指定生成后的字节码位置
redefine热更新代码
使用redefine重新加载新编译好的.class

这里没有重启jvm,发一个请求检验更新字节码是否生效

可以看到打印了新增的日志。
网友评论