Java诊断工具-Arthas入门与实践
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入门与实践相关推荐
- Arthas(1):Java诊断工具Arthas入门教程
文章目录 前言 第一节 Arthas 能为你做什么? 第二节 环境准备 第三节 快速入门 1. 启动math-game 2. 启动arthas 3. 查看dashboard 4. 通过 thread ...
- 阿里开源的Java诊断工具——Arthas
文章目录 1 问题背景 2 前言 3 Arthas有什么作用 4 入门小实践 5 SpringBoot应用.Arthas.Arthas Tunnel Server之间的关系 1 问题背景 线上生产环境 ...
- 阿里Java诊断工具 arthas - 生产环境反编译动态修改程序调试应用
阿里Java诊断工具 arthas - 生产环境反编译动态修改程序调试应用 一.arthas 上篇文章我们借助arthas监测线上系统的运行信息.排查程序运行缓慢问题,尽管这样已经非常好了,但是还是会 ...
- 阿里巴巴开源的 Java 诊断工具Arthas【入门篇】
前面: 各位老铁们,好久没和大家见面了,最近一直躲在家里不敢出来门,过着像猪的生活..... 吃喝拉撒睡觉.远程在家办公一段时间也是遇到了比较棘手的问题.所以没有顾得上来和大家分享了,不过大家放心,从 ...
- java诊断工具-Arthas(阿尔赛斯)入门
Arthas是什么? Arthas 是Alibaba开源的Java诊断工具. 当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决: 这个类从哪个 jar 包加载的?为什么会报各种类相关的 E ...
- 阿里内部的那个牛逼带闪电的Java诊断工具arthas终于开源了
在阿里巴巴内部,有很多自研工具供开发者使用,其中有一款工具,是几乎每个Java开发都使用过的工具,那就是Arthas,这是一款Java诊断工具,是一款牛逼带闪电的工具.该工具已于2018年9月份开源. ...
- Java 诊断工具Arthas初识、安装及试用
目录 功能 使用方式 使用实例 参考 功能 监控jvm运行状态 定位应用热点,生成火焰图 具体jar包来源等 使用方式 win10本地方式 linux本地方式 docker镜像方式 idea插件方式 ...
- Java诊断工具Arthas使用说明
Arthas简介 当你遇到以下类似问题而束手无策时,Arthas 可以帮助你解决: 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception? 我改的代码为什么没有执行到?难道是我没 ...
- Java诊断工具 Arthas
是什么 Arthas 是Alibaba开源的Java诊断工具,深受开发者喜爱.在线排查问题,无需重启:动态跟踪Java代码:实时监控JVM状态.可以解决如下常见问题: 这个类从哪个 j ...
最新文章
- reddit android app,reddit安卓版app
- 数据库SQL语句学习笔记(4)-过滤数据
- 【最详细】测试点分析_1051 复数乘法 (15分)_14行代码AC
- Intent.createChooser文件选择
- css 解析 开源库_干货 | python库大全,全面高效
- 修改百度搜索结果的标题
- rhel6.3yum源的几种配置解析
- 机器学习基础(三十四)—— 协同过滤(之获得推荐)
- 《那些年啊,那些事——一个程序员的奋斗史》——81
- Android常用抓包工具—Charls(青花瓷)
- 用Python制作温度换算模块
- 核苷酸和氨基酸蛋白序列转换的工具
- 【K8S系列】深入解析 k8s:入门指南(一)
- 大场景室内点云标注数据集S3DIS介绍
- opencv处理图像数据时候,出现图像全黑
- [源码解析] PyTorch 流水线并行实现 (1)--基础知识
- 数据集成的两种架构:ELT和ETL
- 一转头如释重负,一瞬间心如刀绞
- python爬虫 requests+lxml爬取前程无忧网之模拟浏览器登录
- 普洱茶为什么是357克,普洱茶357克的由来