(一)Arthas(阿尔萨斯)是阿里巴巴开源的 Java 诊断工具,能够查看应用的load,内存,gc,线程等状态信息;
并能在不修改应用代码的情况下,对业务问题进行诊断,包括查看方法调用的出入参、异常,监测方法执行耗时,类加载信息等,大大提升线上问题排查效率
(二)这边先贴出两个地址:
官方文档地址:
https://alibaba.github.io/arthas/
GitHub源码地址:
https://github.com/alibaba/arthas/
(三)Remote:
的核心是JPDA(JVM的调试标准)框架,支持设置断点及线程级的调试同时,不同的JVM通过接口的协议联系,本地的Java文件在远程JVM建立联系和通信。
3.1.有两种模式:
Attach:调试服务端(被调试远程运行的机器)启动一个端口等待我们(调试客户端)去连接
Socket Listen :调试客户端)去监听一个端口,当调试服务端准备好了,就会进行连接
3.2.Remote 最常用的功能:
a. 最常用的是支持断点调试,在本地能通过设置断点调试远端的代码,从而排查问题。
3.3.Remote需要注意的点:
a.本地代码和远程需要调试的代码和远程调试的目标服务器的代码要一直,才能断点到程序
3.4.怎么做?
1.在idea上创建Remote监听目标服务的的ip 端口入下图
2.在远程服务器开启远程调试配置:
a.tomcat作为服务器:
tomcat 6
开启debug 调试模式 在catalina.sh中最上部分添加这句:declare -x CATALINA_OPTS=”-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8081″
tomcat 7以上
开启debug 调试模式 catalina.bat jpda start
b.jar直接运行添加参数
-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=2345
3.5 Remote
存在不够友好的地方:
1.入侵性太强,设置断点会阻止远程整个应用程序运行。
2.缺少直观可观测的数据输出。
3.缺少直观的堆栈跟踪。
(四)
Arthas 能解决什么问题
在官方文档上是这么描述的:
当你遇到以下类似问题而束手无策时,
Arthas
可以帮助你解决:
-
这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
-
我改的代码为什么没有执行到?难道是我没 commit?分支搞错了? —jsd
-
遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗? –trace watch tt stack
-
线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现! –dashboard
-
是否有一个全局视角来查看系统的运行状况? – jvm thread
-
有什么办法可以监控到JVM的实时运行状态? – jvm
-
怎么快速定位应用的热点,生成火焰图?
在讲这个之前先来讲一下Arthas的工作原理,是怎么解决Remote不能解决问题。
(五)原理:
.java5 的时候使用
java.lang.instrucment
可以在启动时加载Agent对JVM底层组件进行访问
. java6 之后则可以通过进程间通讯的方法,先
VirtualMachine.attach(pid)
,然后动态加载自定义的agent代理
virtualMachine.loadAgent
.
通过Java Tool API中的attach方式,我们可以很方便地在运行过程中动态地设置加载代理类,以达到能够对JVM底层组件进行访问
Arthas 是通过进程建的通讯方法,实现本地和远程目标服务器两个JVM的之间的通讯。
看下源码:
https://github.com/alibaba/arthas/
主要分成下面几大模块:
- Agent – VM 加载的自定义 Agent
- Client – Telnet 客户端实现
- Core – Arthas 核心实现,包含连接 VM, 解析各类命令等
- Site – Arthas 的帮助手册站点内容
Arthas 的工作过程:连接进程—->反编译class—->查询指定加载的class(各种命令)
a.连接进程:
是会将本地启动的所有 Java 进程,以 pid 做为文件名存放在Java 的临时目录中。这个列表,遍历这些文件即可得出来。
在选择好进程之后,就可以链接到指定进程了,这边是用了tools.jar 包中的
com.sun.tools.attach.VirtualMachine
以及
VirtualMachine.attach(pid)
这种方式来实现的。
我们将自定义的Agenthe VM进行通讯—>实际上就是arthas-core.jar中:通过
VirtualMachine
, 可以attach到当前指定的pid上,或者是通过
VirtualMachineDescriptor
实现指定进程的attach
virtualMachine.loadAgent(configure.getArthasAgent(),configure.getArthasCore() + “;” + configure.toString());
类的反编译和指定类加载查询这边不在多讲,有兴趣的可以到GitHub上看源码。
(六)Arthas的使用:这边我们主要以Alibaba 在IDEA的插件 Alibaba Cloud View 来讲解。
1.首先安装 Alibaba Cloud Toolkit
2.配置目标服务器:配置目标服务的IP端口和用户名密码
3.在第一次进入arthas的Dashboard界面的时候,会在目标服务器自动下载 arthas-boot.jar的包。
实际上是在目标服务器上执行了:java -jar /root/.arthas/lib/3.2.0/arthas/arthas-boot.jar
4.arthas常用命令的介绍:我这边把命令分类整理了下:
4.1基础命令:
- help——查看命令帮助信息
- cls——清空当前屏幕区域
- session——查看当前会话的信息
-
reset
——重置增强类,将被 Arthas 增强过的类全部还原,Arthas 服务端关闭时会重置所有增强过的类 - version——输出当前目标 Java 进程所加载的 Arthas 版本号
- history——打印命令历史
- quit——退出当前 Arthas 客户端,其他 Arthas 客户端不受影响
- shutdown——关闭 Arthas 服务端,所有 Arthas 客户端全部退出
-
keymap
——Arthas快捷键列表及自定义快捷键
4.2jvm相关:
-
dashboard
——当前系统的实时数据面板 -
thread
——查看当前 JVM 的线程堆栈信息 -
jvm
——查看当前 JVM 的信息 -
sysprop
——查看和修改JVM的系统属性 -
sysenv
——查看JVM的环境变量 -
getstatic
——查看类的静态属性 -
New!
ognl
——执行ognl表达式
4.3class相关:
-
sc
——查看JVM已加载的类信息 -
sm
——查看已加载类的方法信息 -
jad
——反编译指定已加载类的源码 -
mc
——内存编绎器,内存编绎.java文件为.class文件 -
redefine
——加载外部的文件,redefine到JVM里 -
dump
——dump 已加载类的 byte code 到特定目录 -
classloader
——查看classloader的继承树,urls,类加载信息,使用classloader去getResource
4.4monitor/watch/trace相关:
请注意,这些命令,都通过字节码增强技术来实现的,会在指定类的方法中插入一些切面来实现数据统计和观测,因此在线上、预发使用时,请尽量明确需要观测的类、方法以及条件,诊断结束要执行或将增强过的类执行 命令。
-
monitor
——方法执行监控 -
watch
——方法执行数据观测 -
trace
——方法内部调用路径,并输出方法路径上的每个节点上耗时 -
stack
——输出当前方法被调用的调用路径 -
tt
——方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测
5.最常用的命令和场景:这边记录了几个常用命令和场景使用:
1.查看目标服务器应用程序的jvm信息:
2.方法性能的排查和跟踪,如果我们在实际使用过程中发现某个接口很耗时,但是无法在本地环境复现的时候我们可以通过arthas的trace来跟踪,他会输出方法内部路径每个节点的耗时。
使用demo: trace 类路径 类中的接口方法
trace cn.vv.oa.module.workflow.controller.WorkflowApplyController getList
trace命令只会trace匹配到的函数里的子调用,并不会向下trace多层。因为trace是代价比较贵的,多层trace可能会导致最终要trace的类和函数非常多
提供正则匹配
trace -E com.test.ClassA|org.test.ClassB method1|method2|method3
trace -E cn.vv.oa.module.workflow.controller.MyProcessController getMyProcessList|getMyProcessDetail
3.tt 命令的使用:视察环境现场 还原环境现场 的参数 返回值 异常 便于回溯比对接口不同时间的现场 有点时光机的意思
tt -t cn.vv.oa.module.workflow.controller.WorkflowApplyController getList 视察接口访问概况
tt -l 还原被tt -t 接口访问的记录
tt -i index 根据index展示接口访问的详情
4.watch:观察到的范围为:
返回值
、
抛出异常
、
入参
返回值
抛出异常
入参
可以通过OGNL表达式来观测接口访问情况。
4个观察事件点,即
-b
方法调用前,
-e
方法异常后,
-s
方法返回后,
-f
方法结束后
target:调用方法的对象实例
params:方法参数
returnObj:返回值,如果有的话
returnExp:异常,如果有的话
watch
cn.vv.oa.module.org
.controller.OrganizationController getOrgTree “{params,returnExp,returnObj}” -x 3 (3指定观察点的展开的层数,默认是1)
watch
cn.vv.oa.module.org
.controller.OrganizationController getOrgTree “{params,target,returnObj}” -x 3 -b -s -n 3 (观察调用方法前和返回后)
watch cn.vv.oa.module.workflow.controller.WorkflowApplyController getList “{params,target,returnObj}” ‘#cost>200’ -x 3 (过滤掉执行时间小于200ms的调用)
5.stack 跟踪方法的堆栈信息
stack cn.vv.oa.module.workflow.controller.WorkflowApplyController getList
6. 场景:我改的代码为什么没有执行到?难道是我没 commit?分支搞错了? (实际上就是 JVM 中实际运行的 class 的 byte code 反编译成 java 代码)—jad
jad cn.vv.oa.module.workflow.controller.WorkflowApplyController getList (指定方法)
jad cn.vv.oa.module.workflow.controller.WorkflowApplyController (指定类)
案例一:检查死锁:
thread -b
案例二:检查代码是否丢失,往常的做法我们会先把在运行的jar包下载下来解压在找到相应的类文件查看代码是否丢失。
使用Arthas 我们可以在本地使用阿里的插件使用:jad 例如: jad cn.vv.oa.module.workflow.controller.WorkflowApplyController 反编译查看源码。
案例三:接口性能排查 GMS在预发发现获取流程详情的接口访问很慢,但是在本地,开发,测试其实无法复现。后面是使用arthas 的trace命令排查出的。
trace cn.vv.oa.module.workflow.controller.MyProcessController getMyProcessDetail
总结:arthas 能解决很多远程调试和排错的问题,但是不是万能的,配合日志/remote等其他工具,在不同的环境适当使用才能发挥它的作用。