Java诊断工具-Arthas入门与实践

目录

  • Java诊断工具-Arthas入门与实践
      • 什么是Arthas?
      • Arthas能做什么?
      • 我在哪里可以下载Arthas?
    • 快速入门
      • 1. 下载并运行math-game
      • 2. 使用Arthas粘附目标程序
      • 3. jad反编译源码
      • 4. watch查看方法返回结果
      • 5. trace打印内部调用路径
      • 6. stack打印被调用路径
    • 进阶操作
      • 1.tt时空隧道
      • 2.getstatic查看静态属性
      • 3.调用静态方法
    • 高阶操作
      • 1. 调用由spring管理的类的方法
      • 2. 实时修改线上代码
    • 参考文献:

什么是Arthas?

Arthas是Alibaba开源的Java诊断工具,支持JDK 6+,支持Linux/Mac/Windows,采用命令行交互模式。

Arthas能做什么?

如果你是一个成熟的Java研发,相信你一定遇到过如下问题:
1.我改的代码怎么没效果?难道打包有问题?
2.擦,这里没怎没有加日志啊,为了加日志上次线又很麻烦!
3.这段代码在我本地好好的,怎么线上就有问题呢?
4.服务好端端的怎么假死了?希望能看到服务的实时状态,知道它到底在做什么!
5.这个服务似乎加载了一个错误的类,但是我不知道他是从哪个jar里加载来的!
… …

以上问题,借助Arthas都可以迎刃而解。

我在哪里可以下载Arthas?

点击这里下载Arthas-3.5.3,解压后即可使用

诚然,很多jvm相关的问题我们可以通过jdk本身提供的各种命令进行解决,但使用起来不够直观,功能也不完善,所以我们才需要借助Arthas这样的三方诊断工具,下边我们由浅入深的介绍Arthas的各种操作,如果你之前没有接触过诊断工具,相信它会极大的提升你的debug速度,助你快速定位问题。开始前建议先喝一杯水,因为下边全是干货。

快速入门

在这一小节里,我们将运行一个math-game的简单程序,这个程序每隔一秒生成一个随机数,再执行质因数分解,并打印出分解结果。我们使用Arthas来attach这个程序,来初步掌握Arthas的使用。

1. 下载并运行math-game

curl -O https://arthas.aliyun.com/math-game.jar
java -jar math-game.jar

程序运行起来后,你会看到如下日志:

这就代表我们正常启动了

2. 使用Arthas粘附目标程序

这里务必使用与启动math-game相同的账户,因为Arthas只能粘附当前用户发起的java进程:

sh as.sh


arthas会列出当前用户启动的java进程列表,如果你在这里无法认出哪个是你的目标进程,可以Ctrl + C退出,使用ps -ef | grep <关键字>来找到你的进程pid,再来这里找对应进程。
当然,本次我们很容易就能看出3号进程是我们的目标,于是输入3,arthas就会尝试去attach(粘附)这个进程:

看到这个ARTHAS的大logo,就证明attach成功了。

3. jad反编译源码

到这里,我们似乎还不知道这个jar里究竟写了什么内容,好在上图中,arthas已经为我们提示了这个jar的main class:demo.MatchGame,我们可以使用jad命令直接对其进行反编译:

jad demo.MathGame


可以看出,我们成功的反编译了main class的源码,并且arthas为我们额外展示了它的classLoader和所属jar。如果我们不想要这些额外信息,可以使用–source-only参数,仅展示源码。

4. watch查看方法返回结果

通过阅读源码,我们可以知道我们看到的日志,是通过demo.MathGame#primeFactors这个方法打印出来的,我们可以直接使用watch命令对这个方法进行观测,查看他的入参与返回结果:

watch demo.MathGame primeFactors {params,returnObj}

这条命令由四部分组成,分别是 watch命令,目标类的全限定名,目标方法,以及我们要看哪些信息,params即全部参数,returnObj是返回结果,这是ognl表达式的写法, 关于ognl详细可以看这里:apache官方ognl介绍当然,眼下我们还不需要关注这么多,执行命令得到以下结果:

由于程序中每秒都会调用一次这个方法,所以arthas会不断打印,可以按Q退出这次watch。仔细观察打印的结果,我们会发现虽然arthas打印了参数和结果,但是只显示了Object,并没有显示它的内容,这显然是没有意义的,原因是我们打印的遍历层次不够,我们在刚才这条命令的尾部,追加 -x 3参数,意思是,对params和returnObj最多向下遍历3层:

watch demo.MathGame primeFactors {params,returnObj} -x 3


这样,我们就能清晰的看到本次的入参是1,返回结果是2,59,和73组成的ArrayList。

5. trace打印内部调用路径

有时候,我们在线上会遇到这样的问题:
某个方法执行时间特别长,但是它的内部调用很深,我们不知道是哪个部分耗费的时间久。
这时候,就该trace出场了:

trace demo.MathGame primeFactors

我们使用trace跟踪这个方法,可以看到每一次方法内部调用路径信息:

除了调用层级外,我们还能在每次调用前看到当前函数耗费的时间,这对我们进行性能优化是非常有用的。

6. stack打印被调用路径

与上一个方法类似的,我们在项目中,可能会碰到同一个函数被多处调用的情况,stack命令可以为我们展示出调用路径:

stack demo.MathGame primeFactors


arthas还用非常多的实用命令,包括与虚拟机相关的 jvm, dashboard, vmoption,classloader,与线程相关的thread,以及生成火焰图的profiler等等,此处不一一介绍,可以参考arthas官方文档:

arthas命令列表

进阶操作

在快速入门中,我们使用了watch,stack,trace等命令,帮助我们观测程序执行情况,但这些都是被动观测,也就是说,只有等到程序执行到这里时,我们才能看到结果。有些时候,这不是很方便,比如:
1.如果这是个每天凌晨运行的定时任务怎么办?我不可能凌晨守在这里watch!
2.我的程序里在某个静态Map中get了一个key,我们不可能去watch HashMap的get方法,因为程序里有太多get了!(当然这种情况arthas也可以通过ognl有其他处理手段,但这里提供一种更优解)
下面这些命令,可以解决这些场景

1.tt时空隧道

watch命令固然好用,但是他对我们统计历史情况来说,不是很方便,而且使用watch需要我们提前想好要查看的表达式内容,所以我们有了tt这个命令,他可以帮我们记录下每一次调用时,当时的环境信息,并且给每一次调用提供了一个唯一 id,方便我们日后跟踪和replay。
使用起来很简单:

tt -t demo.MathGame primeFactors


可以看出,tt命令为我们记录下了每次请求的时间,耗时,是否正常返回,是否有异常等等信息,如果我们要查看详细的信息,可以使用 -i参数加index来查询,-s参数加ognl表达式来进行搜索,使用-play参数重新运行此请求,使用-w通过ognl表达式进行操作等等,此处不再赘述,可以参考官方文档。

2.getstatic查看静态属性

getstatic命令可以让我们直接查看某个类的静态成员,使用起来非常简单:

getstatic demo.MathGame random

3.调用静态方法

除了查看静态成员外,我们还可以通过ognl表达式来调用静态方法:

ognl '@System@out.println("haha")'

@代表这是一个静态成员,上例中,我们调用了System.out.println这个静态方法:

当然,由于这个方法没有返回值,我们无法在这里看到任何结果,但是这个调用方法,一样可以应用在我们项目中的其他静态方法上。

讲到这里,你的脑子里肯定会提出问题:你这说了半天,全是静态成员和静态方法啊!我如果想调用一个非静态方法怎么办?现在都是Spring项目,我想调用一个Controller或者service的方法怎么办?我想看一个Autowired进来的变量怎么办?balabalaba…

别急,下边这部分就是为你准备的

高阶操作

1. 调用由spring管理的类的方法

我们知道,我们在Spring项目中,注入的所有bean,都是由springContext进行管理的,也就是说,只要拿到springContext这个对象,我们就能通过它get到我们想要的实例,并调用其中的方法,或查看其成员,为所欲为。
问题是如何拿到这个springContext。学习过springmvc的同学一定对RequestMappingHandlerAdapter这个类不陌生,他可以帮我们的请求找到对应的Handler来处理,而这个类中,就包含我们想要的context对象。

首先,使用tt对其进行跟踪,并从页面请求一次这个服务的任意接口:

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


可以看到我们成功的记录到了这次请求,接下来,我们通过-w参数,执行ognl来获取context:

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


如图,我们成功获取了context对象,接下来,我们可以直接调用getBean方法,获取我们的service,并执行他的queryExample方法:

tt -i 1000 -w 'target.getApplicationContext().getBean("msgServiceImpl").queryExample("test")'

遗憾的是,执行失败了。执行结果提示出现了空指针异常,跟踪arthas的日志发现,原因是我们这个queryExample内部依赖了一个mybatis的mapper对象进行sql查询,而这个对象现在是空的,并没有被注入进来,调用时必然空指针了,所以我们的表达式需要写的再复杂一些:

tt -i 1000 -w '#mapper=target.getApplicationContext().getBean("msgNotifyMapper"),#service=target.getApplicationContext().getBean("msgServiceImpl"),#service.msgNotifyMapper=#mapper,#service.queryExample("test")'

可能看到这里你会有些晕,不要慌,我们拆开看:

tt -i 1000 -w
'
//获得Mapper对象的bean
#mapper=target.getApplicationContext().getBean("msgNotifyMapper"),
//获得service对象的bean
#service=target.getApplicationContext().getBean("msgServiceImpl"),
//将service中的mapper对象赋值为我们刚获得的mapper bean
#service.msgNotifyMapper=#mapper,
//调用query方法
#service.queryExample("test")
'

这样,我们就能成功的调用queryExample方法!可以看出,使用ognl,我们可以完成更多复杂的逻辑,也就能根据我们的需求,做出更细致的操作~但有时候,我们靠这样的方法还是不能够准确定位问题,我们需要把线上的代码按我们的需求做一些调整,比如修改某个判断条件,添加一行日志,调整循环的次数等等,这时候,我们可以借助更多命令,来实时热部署线上代码。

2. 实时修改线上代码

在开头,我们学习过jad的使用,但那时,我们只是把源码反编译并展示在屏幕上,
实际上,我们可以将它保存成java文件,就和linux命令一样:

jad --source-only demo.MathGame > /Users/sunyuhan/tmpFile/MathGame.java


我们将源码保存下来后,就可以使用vim或者下载下来进行编辑了,编辑后,使用mc命令内存编译回class:

mc /Users/sunyuhan/tmpFile/MathGame.java -d /Users/sunyuhan/tmpFile/MathGame.class


最后,重点来了,使用retransform命令,将这个class替换掉jvm中正在运行的class:

retransform /Users/sunyuhan/tmpFile/MathGame.class/demo/MathGame.class


无需中断项目,就可以完成代码的热部署!

最后,还是有一些需要注意的点,虽然retransform非常实用,但是我仍然不建议你在生产环境这样做,没有走标准的测试流程,生产环境的代码不应当被随意的改变,这是一个非常危险的操作!并且由于我们是在jvm层面做的调整,在你重启整个项目后,重新从部署的包中加载内容回jvm,仍然是旧的内容,除非我们将这些jar中的class也进行替换。


参考文献:

  • [1].arthas官方文档 https://arthas.aliyun.com/doc/index.html
  • [2].ognl官方文档 https://commons.apache.org/proper/commons-ognl/language-guide.html
  • [3].arthas项目github https://github.com/alibaba/arthas/issues/71

Java诊断工具-Arthas入门与实践相关推荐

  1. Arthas(1):Java诊断工具Arthas入门教程

    文章目录 前言 第一节 Arthas 能为你做什么? 第二节 环境准备 第三节 快速入门 1. 启动math-game 2. 启动arthas 3. 查看dashboard 4. 通过 thread ...

  2. 阿里开源的Java诊断工具——Arthas

    文章目录 1 问题背景 2 前言 3 Arthas有什么作用 4 入门小实践 5 SpringBoot应用.Arthas.Arthas Tunnel Server之间的关系 1 问题背景 线上生产环境 ...

  3. 阿里Java诊断工具 arthas - 生产环境反编译动态修改程序调试应用

    阿里Java诊断工具 arthas - 生产环境反编译动态修改程序调试应用 一.arthas 上篇文章我们借助arthas监测线上系统的运行信息.排查程序运行缓慢问题,尽管这样已经非常好了,但是还是会 ...

  4. 阿里巴巴开源的 Java 诊断工具Arthas【入门篇】

    前面: 各位老铁们,好久没和大家见面了,最近一直躲在家里不敢出来门,过着像猪的生活..... 吃喝拉撒睡觉.远程在家办公一段时间也是遇到了比较棘手的问题.所以没有顾得上来和大家分享了,不过大家放心,从 ...

  5. java诊断工具-Arthas(阿尔赛斯)入门

    Arthas是什么? Arthas 是Alibaba开源的Java诊断工具. 当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决: 这个类从哪个 jar 包加载的?为什么会报各种类相关的 E ...

  6. 阿里内部的那个牛逼带闪电的Java诊断工具arthas终于开源了

    在阿里巴巴内部,有很多自研工具供开发者使用,其中有一款工具,是几乎每个Java开发都使用过的工具,那就是Arthas,这是一款Java诊断工具,是一款牛逼带闪电的工具.该工具已于2018年9月份开源. ...

  7. Java 诊断工具Arthas初识、安装及试用

    目录 功能 使用方式 使用实例 参考 功能 监控jvm运行状态 定位应用热点,生成火焰图 具体jar包来源等 使用方式 win10本地方式 linux本地方式 docker镜像方式 idea插件方式 ...

  8. Java诊断工具Arthas使用说明

    Arthas简介 当你遇到以下类似问题而束手无策时,Arthas 可以帮助你解决: 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception? 我改的代码为什么没有执行到?难道是我没 ...

  9. Java诊断工具 Arthas

    是什么         Arthas 是Alibaba开源的Java诊断工具,深受开发者喜爱.在线排查问题,无需重启:动态跟踪Java代码:实时监控JVM状态.可以解决如下常见问题: 这个类从哪个 j ...

最新文章

  1. reddit android app,reddit安卓版app
  2. 数据库SQL语句学习笔记(4)-过滤数据
  3. 【最详细】测试点分析_1051 复数乘法 (15分)_14行代码AC
  4. Intent.createChooser文件选择
  5. css 解析 开源库_干货 | python库大全,全面高效
  6. 修改百度搜索结果的标题
  7. rhel6.3yum源的几种配置解析
  8. 机器学习基础(三十四)—— 协同过滤(之获得推荐)
  9. 《那些年啊,那些事——一个程序员的奋斗史》——81
  10. Android常用抓包工具—Charls(青花瓷)
  11. 用Python制作温度换算模块
  12. 核苷酸和氨基酸蛋白序列转换的工具
  13. 【K8S系列】深入解析 k8s:入门指南(一)
  14. 大场景室内点云标注数据集S3DIS介绍
  15. opencv处理图像数据时候,出现图像全黑
  16. [源码解析] PyTorch 流水线并行实现 (1)--基础知识
  17. 数据集成的两种架构:ELT和ETL
  18. 一转头如释重负,一瞬间心如刀绞
  19. python爬虫 requests+lxml爬取前程无忧网之模拟浏览器登录
  20. 普洱茶为什么是357克,普洱茶357克的由来

热门文章

  1. 什么情况下需要破坏双亲委派模型
  2. C语言之struct
  3. 19、基于STM32的电子打铃器
  4. Redis重大版本整理(Redis2.6-Redis6.0)
  5. 开放redis指定端口连接方法
  6. 怎么从服务器上文件拷贝下来
  7. 数字电路和模拟电路-1基础知识
  8. Fiddler抓包:详解Fiddler抓包工具软件使用教程
  9. Cannot resolve com.oracle:ojdbc6:11.2.0.3
  10. pyqt 可视化二叉树