Arthas-在线调试利器

我们在开发中不难出现这样的问题:线上某个功能不可用,登上机器查看日志,发现在报错。但为什么报错,翻了半天日志可能也没找到原因,“日志”到用时方恨少,非常后悔当时没有多打日志。
此时,要么选择在线 Debug — 有时候并不那么容易;要么修改代码,增加相关日志打印语句,重新发布部署,而这容易导致问题难以复现。
Arthas 的出现解决了这样的困境。

Arthas(阿尔萨斯),它是由阿里开源的一款 Java 诊断工具,继承自 BTace 和 Greys,提供了 :

  • 系统环境信息、虚拟机信息: (线程信息、内存信息、类加载信息)等的查看、监控。
  • 运行时查看方法执行详情、方法调用链、方法调用统计信息。
  • 提供内存中编译类、反编译加载的类、热加载类等功能

更多详细功能请到官方网站查看。

本系列文章的目的

Arthas 中文文档写的十分详尽,此处不再做文档的搬运工。文章主要是对其做一些归类总结
在阅读下面的内容之前,请先了解 官方命令列表

命令分类

使用 Arthas的第一步就是,熟练运用相关命令,活用相关命令,在真正出现线上问题,排查问题才能行云流水,一气呵成。下面对命令按照使用场景进行了分类分为:

  • 公共工具:sc、sm、stack

  • 线上异常排查:watch、tt

  • 动态代码执行: ognl

  • 热更新: jad、mc、redefine、classloader、dump

  • 性能分析:jvm、trace、thread

  • 彩蛋::july、thanks

公共工具

用于查找类、方法、方法调用栈。大多数命令使用前都需要知道类和方法,这些公共的工具提供了快速定位目标的方法(通过通配符或者正则表达式)

线上异常排查

线上排查问题的流程一般是:

  1. 查看日志,找到具体报错异常栈和报错位置,也可以使用 sc,sm,stack 等工具找到方法调用入口,再使用 tt 或者 watch -e 查看异常栈和报错位置

  2. 查看方法调用细节,洞悉方法执行现场。

    有两个选择:使用tt (TimeTunnel 时空隧道),使用 watch

    tt 命令

    可以保存当前方法调用的详细信息,包括入参、返回值、异常信息(如果有的话),方便快速定位。也可以重放调用(但是不一定准确)

    watch 命令

    观察某个方法的详情,具体信息可以在后面跟表达式指定。例如: watch demo.MathGame primeFactors "{params,returnObj}" 可以查看参数,返回值。

    如何选择:

    tt 可以保存多个方法调用现场,方便后续查看、重放。但是有时候查看、重放不一定准确,原因是tt 只是保存当时环境的对象引用,当对象值改变之后,你查看的时候看到的是最新的值,而不是当时调用的值,这时,需要使用 watch 命令准确的查看方法调用的现场

动态代码执行

上一步的异常排查发现出错位置和原因,如果仍然不知道如何修改,需要做一些探索,就需要动态代码执行工具了。Arthas 通过 ognl 表达式查看一些静态字段值,执行一些代码片段等。注意,getstatic 可以替代 ognl 查看类的静态字段的功能,但不建议学习,增加学习成本。

热更新

动态代码执行适合于执行一些表达式类短小精悍代码,对于大段代码就显得力不从心。于是就需要热更新技术了。
热更新工具箱包括 jad、mc、redefine、classloader、dump。热更新一段代码一般遵循一些顺序:

  1. 反编译:使用jad 反编译已经加载的字节码,如果觉得反编译效果不好,可以使用 dump 转储字节码文件,然后使用其他工具反编译为代码。
  2. 修改代码:修改想要更新的代码
  3. 编译:可以使用 mc 命令编译更新的代码(需要指定class loader),也可以使用 idea 等第三方工具编译好,上传到服务器
  4. 加载新的类:使用 redfine 命令加载

redefine 使用限制:

  • 不支持新增属性、方法
  • 正在运行的函数 redefine 后不会生效,只有方法运行完后下次运行才会生效。

使用技巧

匹配多个方法

如果想匹配多个方法,可以使用正则表达式,命令后面添加 -E 开启:

1
trace -E 'io\.netty\.channel\.nio\.NioEventLoop|io\.netty\.util\.concurrent\.SingleThreadEventExecutor'  'select|processSelectedKeys|runAllTasks' '@Thread@currentThread().getName().contains("IO-HTTP-WORKER-IOPool")&&#cost>500'

退出 Arthas

使用 exit/quit 命令结束当前回话,关闭客户端,但不会关闭服务端。使用 jps 查看,会看到Arthas 还在运行。需要使用 shutdown 命令完全关闭服务端。

参考文档

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