在以前的文章中,我介绍了使用 Btrace 工具进行线上代码的debug (http://www.javashuo.com/article/p-ttklizae-gv.html),其大体原理就是经过字节码注入的方式进行辅助排查。html
能够说,btrace 已经给咱们的开发调试一带来了许多的方便,咱们在上面作任何想要的调试!可是,明显, btrace 的使用仍是有必定成本的,好比:安装应用,写调试脚本...java
因此,今天咱们再来看一大利器: arthas (阿尔萨斯)git
arthas 官网地址:https://alibaba.github.io/arthas/github
arthas 的文档真的写得很是棒,能够说一看就会。web
可是我仍是想写一下一些本身的文档,毕竟咱们每每只会用到其中皮毛功能而已。翻阅其全部文档也仍是有点浪费了!spring
其实,这个问题在前面已回答,并且,你为何要用 btrace ? 同理! 具体理由以下:服务器
真的是超级简单哦;1. 先把 arthas 的 工具jar包下载下来; 2. 运行便可;ide
wget https://alibaba.github.io/arthas/arthas-boot.jar java -jar arthas-boot.jar
请问,还能更简单吗?工具
通过上一步安装,并运行以后,就差很少是图形界面操做了。性能
第一步,arthas 会检测到目前正在有几个运行中的java程序,你只需按照序号选择就就能够了。这里你就彻底置身该应用环境了。接下来就能够 do what ever you want to do 。
下面,我以几个经常使用问题场景,来简要看看其解决方案如何吧!
问题1. 我如何查找某个只知道大概的类,或者说我想确认某个类是否已被系统加载?
经过这个问题,咱们能够确认一点: 我写的代码是否被部署了。固然,若是是对于 war 包,其实这个问题比较容易解决,由于它是一个个的 class 文件,咱们能够直接使用 find 命令查找便可。然而这毕竟只是理想,事实会很复杂!
因此, arthas 怎么查找一个类?
sc *DispatcharServlet # 便可以找到须要的类全路径,若是存在的话
sm org.springframework.web.servlet.DispatcherServlet getHandler # 查看某个方法的信息,若是存在的话
甚至咱们可使用通配符列出全部的方法:
问题2. 如何查看一个class类的具体信息?
虽然经过上面检查类和方法是否存在,可以解决一部分咱们排查代码的问题,可是在咱们只是改动一个方法中的稍稍逻辑时,就没法经过类和方法来确认问题,此时就须要进行反编译后进行查看了!
这事若是要我本身去干,我多半只是将jar包中的class文件,使用 javap 进行反编译成可读字节码,而后很认真地核对类信息! javap 虽然已经在很大程度上减轻了咱们的阅读压力,但仍然门槛很高。
而 使用 arthas 则简单至极:
jad org.springframework.web.servlet.DispatcherServlet # 直接反编译出java 源代码,包含一此额外信息的
问题3. 如何跟踪某个方法的返回值、入参.... ?
这个问题实际上是咱们在用 btrace 这样的工具的大部分时候的初衷!虽然 trace 脚本编写并不复杂,可是千篇一概和频繁地更改,也给咱们带来了许多麻烦。
而这在 arthas 就是一个命令的事!
watch com.test.ob testMethod "{params, returnObj, throwExp}" -e -x 2 # 同时监控入参,返回值,及异常
若是有异常,直接打印出来,不然出入参直接监控,超级方便!
这里有支持复杂的 ognl 语法,实现更复杂逻辑,请参考: https://alibaba.github.io/arthas/watch.html
问题4. 查看最繁忙的线程,以及是否有阻塞状况发生?
查看繁忙的线程,通常咱们能够经过 top 等系统命令进行查看,可是那毕竟要不少个步骤,很麻烦。
而 arthas 则直观明了:
thread -n 3 # 查看最繁忙的三个线程栈信息 thread # 以直观的方式展示全部的线程状况 thread -b #找出当前阻塞其余线程的线程
问题5. 如何验证本身的代码猜测,临时更改代码运行?
可能我就是认为其中有一个数字写错了,致使业务出错,可是不太确认,因此想在线上直接验证下!
基本的经验是,在本地改了代码后,从新打包部署,而后重启观察效果。可是这太慢了!
jad --source-only com.example.demo.arthas.user.UserController > /tmp/UserController.java # 先反编译出class源码 # 而后使用外部工具编辑内容 mc /tmp/UserController.java -d /tmp # 再编译成class # 最后,从新载入定义的类,就能够实时验证你的猜想了 redefine /tmp/com/example/demo/arthas/user/UserController.class
如上,是直接更改线上代码的方式,可是通常好像是编译不成功的。因此,最好是 本地ide 编译成 class 文件后,再上传替换为好!
总之,已经彻底不用重启和发布了!这个功能真的很方便,比起重启带来的代价,真的是不可比的。好比,重启时可能致使负载重分配,选主等等问题,就不是你能控制的了。
问题6. 我如何测试某个方法的性能问题?
这个问题其实咱们通常不太关注,可是当性能成为问题时,则真的要关注了!平时咱们使用 进入打印开始时间,退出打印一个结束时间这种方式,仍是有点low了!
monitor -c 5 demo.MathGame primeFactors
以上命令直接统计 primeFactors 的响应问题:
更多参考:https://alibaba.github.io/arthas/monitor.html
问题7. 更高级的追踪工具!
tt (TimeTumple) : 方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不一样的时间下调用进行观测!
tt -t demo.MathGame primeFactors # 追踪方法的响应时间状况
trace: 输出方法内部调用路径,并输出方法路径上的每一个节点上耗时!
trace demo.MathGame run '#cost > 10' # 据调用耗时过滤
总之,你想要进行的调试,应该都能在这里找到实现方案。去查看文档便可!
我以为 arthas 有几个很是好的理念: 1. 可视化追踪,简单易用; 2. 独立classloader, 方便代码卸载;3. 完善的文档;
其实,咱们排查问题时,老是费尽周折。然而当问题解决时,又发现简单到不行。
阿里老话:结果很重要,过程也很重要!