Arthas-java在线调试工具的使用

一、arthas能干什么?

  1. 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
  2. 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
  3. 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
  4. 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
  5. 是否有一个全局视角来查看系统的运行状况?
  6. 有什么办法可以监控到JVM的实时运行状态?
  7. 怎么快速定位应用的热点,生成火焰图?
  8. 怎样直接从JVM内查找某个类的实例?

Arthas支持JDK 6+,支持Linux/Mac/Windows,采用命令行交互模式,同时提供丰富的 Tab 自动补全功能,进一步方便进行问题的定位和诊断。

二、安装与卸载

2.1 下载全量包

这里介绍离线安装,因为本公司的服务器是内网的。
下载路劲:https://arthas.aliyun.com/doc/download.html
在这里插入图片描述

2.2 上传到服务器并解压

## 利用xshell登录服务器,找个合适的位置,如:/usr/arthas
mkdir -p /usr/arthas
## 直接拖动下载zip包到这个位置完成上传
## 解压
unzui arthas-packaging-3.5.4-doc.zip 

在这里插入图片描述

2.3 卸载

rm -rf ~/.arthas/
rm -rf ~/logs/arthas

三 命令

3.1 基础命令

  1. help—— 帮助文档
  2. cat —— 显示文件内容
  3. grep—— 管道符
  4. pwd—— 获取当前路径
  5. cls —— 清屏
  6. session —— 查看当前会话的信息
  7. reset——重置增强类,将被 Arthas 增强过的类全部还原,Arthas 服务端关闭时会重置所有增强过的类
  8. version——输出当前目标 Java 进程所加载的 Arthas 版本号
  9. quit——退出当前 Arthas 客户端,其他 Arthas 客户端不受影响
  10. stop——关闭 Arthas 服务端,所有 Arthas 客户端全部退出
  11. keymap ——Arthas快捷键列表及自定义快捷键

3.2 JVM相关命令

 1 . ★dashboard——当前系统的实时数据面板
 2 . ★thread——显示线程信息
 3 .jvm——与JVM相关的信息
 4. sysprop——查看或修改系统的属性信息
 5. sysenv——查看当前JVM的环境属性
 6. vmoption——查看,更新VM诊断相关的参数
 7. ★getstatic——获取静态变量 推荐直接使用ognl命令,更加灵活
 8. ★ognl——执行ognl表达式
3.2.1 dashboard -i 5000 -n 5

在这里插入图片描述
实用案例

# 每5s刷新一次共执行5次
dashboard -i 5000 -n 5

这儿有个笔误,里面所有的进程都是指线程,进程比线程要大,一个进程可能包含多个线程。
在这里插入图片描述
在这里插入图片描述

3.2.2 thread

在这里插入图片描述
实用案例

## 指定最忙的5个线程
thread -n 5
## (观察id线程)
thread id   
## 查看死锁的线程
thread -b

在这里插入图片描述
在这里插入图片描述

3.2.3 jvm

使用案例

jvm

类加载相关
在这里插入图片描述
编译相关
在这里插入图片描述
垃圾回收,查看gloabal的垃圾回收是否太频繁
在这里插入图片描述
查看有没有死锁的线程
在这里插入图片描述

3.3 class/classloader相关的命令

sc :search class
sm:search method

1. sc——“Search-Class” 的简写,查看JVM已加载的类信息
2. sm——“Search-Method” 的简写,查看已加载类的方法信息

实例:查询一个类的类加载器的hashcode,这个hashcode在热更新时有用
实例:查询一个类的成员变量

## 查看这个类的详细信息,可以看到它是在哪个包或者它的包路径,之后可以用jad来反编译其中的某个方法。
sc -d *CaseEventManageServiceImpl
## -d 表示detail,查询一个类的类加载器的hashcode,这个hashcode在热更新时有用
sc -d *CaseEventManageServiceImpl  | grep classLoaderHash
## 查询成员变量的值-f filed
sc -d -f *CaseEventManageServiceImpl

在这里插入图片描述

classloader 类加载器的应用场景
1.统计所有类加载器加载的对象的个数
2.查看类加载器的继承树
2.查找某个资源所在的包

## 统计所有类加载器加载的对象的个数
classloader
## 统计所有类加载器加载的对象的个数 带有hashcode
classloader -l
## 加载器树
classloader -t
##查找某个资源所在的包
classloader -c xxxx -r

在这里插入图片描述
查找类文件件所在的包
在这里插入图片描述
查找资源文件所在的包
在这里插入图片描述

在线编译和反编译(https://blog.csdn.net/fen_dou_shao_nian/article/details/122228468)

jad————反编译,把.class 文件编译成.java 文件
mc————Memory Compiler/内存编译器,编译.java文件生成.class。
sc————查找到类加载器的hashcode
redefine————加载外部的class文件

★四、最常用的3条命令

arthas如果半个小时不调用,就会自动退出
如何修改环境变量
watch 的 ognl
显示jdf中的方法 --skipJDKMethod false
只显示大于某个时间的方法 ‘#cost>0.5’

4.1 watch:用于监视方法执行情况

在这里插入图片描述

watch 命令定义了4个观察事件点,即 -b 函数调用前,-e 函数异常后,-s 函数返回后,-f 函数结束后,默认是-f

使用性最全的语句
## 注意:instanceof 需要写类的全路径;#cost 表示接口请求时长
watch com.tiandy.testdemo.TestDemoApplication add  '{params,returnObj,throwExp,target}' 'params.length>0 &&params[0].equals("aaa") && params[0] instanceof java.lang.Integer && params[0].getClass().getName().equals("java.lang.String") && #cost>1000 || params[0].contains("xxx") && params[1]=="abc" && params[2]==100L && params[3].name=="zhangsan" && params[4]["age"]==20 && params[5].size()==10' -n 5  -x 3 
## 第 0个参数的名称是wolrd
params[0].name=="wolrd"
## map中获取age的用法
params[4]["age"]
## list的size
params[5].size()
## 通配符的使用
watch *TestDemoApplica* ?dd '{params,returnObj,throwExp}'  -n 5  -x 3 

通过条件筛选监听方法
在这里插入图片描述
通过通配符筛选,监听方法

在这里插入图片描述

4.2 trace: 方法执行过程

在这里插入图片描述

## 监听add方法,--skipJDKMethod false 不跳jdk的方法,'#cost > 10' 结果大于10毫秒
trace com.tiandy.testdemo.TestDemoApplication add 'params[0] instanceof java.lang.Double && #cost > 10' --skipJDKMethod false

4.3 stack: 输出当前方法的执行路径

在这里插入图片描述

## params.length==0 && #cost>5 无参+运行时长大于5ms
stack com.tiandy.testdemo.TestDemoApplication stringAdd 'params.length==0 && #cost>5'  -n 5 

在这里插入图片描述

★五 tt 时间隧道

TimeTunnel
记录方法的调用记录
通过条件过滤
查看某一次的调用结果
通过索引重新调用之前的方法
-t, --time-tunnel 按照时间记录
-p, --play
-i, --index
-l,–list 列出所有的记录

## 监听所有的类中的所有方法,第一个*表示类,第二个*表示方法
tt -t * *   
## -n 5 此方法比较耗费jvm资源,一定要加上次数
tt -t com.tiandy.testdemo.TestDemoApplication add -n 5 
## 超找方法名为add的片段,s 表示search 搜索
tt -s 'method.name=="add"'
## 查看所有监听的片段信息
tt -l
## 查看index为1003的具体信息
tt -i 1003
## 把1003的请求再执行一次
tt -i 1003 -p
## 查看 index 为1000的请求的method.name,params,returnObj,throwExp 这些信息
tt -w '{method.name,params,returnObj,throwExp}' -x 3 -i 1000
## 删除所有记录
tt --delete-all

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

六、热更新

https://blog.csdn.net/fen_dou_shao_nian/article/details/122228468

六、火焰图

生成火焰图

在这里插入图片描述
在这里插入图片描述

七、Arthas最佳实战

7.1 已经有人在使用arthas,端口被占用

  1. 方法一:增加指定端口号 --telnet-port 9998 --http-port 8855
    实例:
/opt/apache-tomcat/jre/bin/java -jar arthas-boot.jar `ps -ef | grep java_tomcat | grep -v grep | awk '{print $2}'`  --telnet-port 9998 --http-port 8855
  1. 方法二:关闭之前的arthas,再打开
    执行/opt/apache-tomcat/jre/bin/java -jar arthas-client.jar ,进入正在使用或者未关闭的arthas服务,执行stop,关闭所有的arthas客户端服务,执行正常的启动。

7.2 排查cpu过高

# 第一步:xshell中执行 找到占用cpu最高的【进程】
top -H -p pid 
若果存在printf "%x\n" tid   tid一直占用cpu的【线程id】
printf "%x\n" tid
# 第二步:使用thread看看线程cpu占用情况或dashbord也可以看到
thread -n 3  
thread pid 显示指定线程的运行堆栈
# 第三步:拿到这个堆栈后反编译看代码,XXX代表类路径,xxx代表方法
jad --source-only XXX xxx
#★指定最忙的前N个线程并打印堆栈
thread -n pid 
thread -b 找出当前阻塞其他线程的线程
thread -i  指定采样时间间隔 (如:thread -n 3 -i 1000,每秒统计最忙的前三个线层)

7.3 查看静态变量

实例

getstatic com.aaa.bbb formInfoMap

7.4 方法过多时观察方法,解决方法重载

只有一个参数
tt -t *Test print params.length1
指定参数类型
tt -t *Test print ‘params[1] instanceof Integer’
指定或包含参数值
tt -t *Test print params[0].mobile
"13989838402"
tt -t *Test print params[0].mobile.contains(“13989838402”)

7.5 ★几种常用的条件表达式

tt -t *Test print params.length==1
tt -t *Test print 'params[1] instanceof Integer'
tt -t *Test print params[0].mobile=="13989838402"
tt -t *Test print params[0].contains("13989838402")
tt -t *Test print params[0].equals("13989838402")

## 执行时长大于20毫秒
watch *Test print '{params,returnObj,throwExp}' ‘#cost>200’  -n 1  -x 3 
watch *Test print '{params[0],params[1],returnObj,throwExp}' ‘#cost>200’  -n 1  -x 3 

7.6 ★ognl条件过滤

ognl学习网站:https://codeleading.com/article/42313530257/

OGNL支持各种纷繁复杂的表达式。但是最最基本的表达式的原型,是将对象的引用值用点串联起来,从左到右,每一次表达式计算返回的结果成为当前对象,后面部分接着在当前对象上进行计算,一直到全部表达式计算完成,返回最后得到的对象。OGNL则针对这条基本原则进行不断的扩充,从而使之支持对象树、数组、容器的访问,甚至是类似SQL中的投影选择等操作。

  1. 基本对象树的访问
    对象树的访问就是通过使用点号将对象的引用串联起来进行。
    例如:xxxx,xxxx.xxxx,xxxx. xxxx. xxxx. xxxx. xxxx
  2. 对容器变量的访问
    对容器变量的访问,通过#符号加上表达式进行。
    例如:#xxxx,#xxxx. xxxx,#xxxx.xxxxx. xxxx. xxxx. xxxx
  3. 使用操作符号
    OGNL表达式中能使用的操作符基本跟Java里的操作符一样,除了能使用 +, -, *, /, ++, --, ==, !=, = 等操作符之外,还能使用 mod, in, not in等。
  4. 容器、数组、对象
    OGNL支持对数组和ArrayList等容器的顺序访问:例如:group.users[0]
    同时,OGNL支持对Map的按键值查找:
    例如:#session[‘mySessionPropKey’]
    不仅如此,OGNL还支持容器的构造的表达式:
    例如:{“green”, “red”, “blue”}构造一个List,#{“key1” : “value1”, “key2” : “value2”, “key3” : “value3”}构造一个Map
    你也可以通过任意类对象的构造函数进行对象新建:
    例如:new Java.net.URL(“xxxxxx/”)
  5. 对静态方法或变量的访问
    要引用类的静态方法和字段,他们的表达方式是一样的@class@member或者@class@method(args):
    例如:@com.javaeye.core.Resource@ENABLE,@com.javaeye.core.Resource@getAllResources
  6. 方法调用
    直接通过类似Java的方法调用方式进行,你甚至可以传递参数:
    例如:user.getName(),group.users.size(),group.containsUser(#requestUser)
  7. 投影和选择
    OGNL支持类似数据库中的投影(projection) 和选择(selection)。
    投影就是选出集合中每个元素的相同属性组成新的集合,类似于关系数据库的字段操作。投影操作语法为 collection.{XXX},其中XXX 是这个集合中每个元素的公共属性。
    例如:group.userList.{username}将获得某个group中的所有user的name的列表。
    选择就是过滤满足selection 条件的集合元素,类似于关系数据库的纪录操作。选择操作的语法为:collection.{X YYY},其中X 是一个选择操作符,后面则是选择用的逻辑表达式。而选择操作符有三种:
    ? 选择满足条件的所有元素
    ^ 选择满足条件的第一个元素
    $ 选择满足条件的最后一个元素
    例如:group.userList.{? #txxx.xxx != null}将获得某个group中user的name不为空的user的列表。
7.6.1 投影和选择 类似与java中stream方法

在这里插入图片描述

watch com.xxx.xxx.xxx.business.controller.CaseFileController queryCaseFilePage '{params[0].sOrgId,returnObj.content.{? 1==1}.{? #this.sCurrentLocation=="\u6848\u7ba1\u5ba4\u002d\u0031\u53f7\u67dc\u5b50\u002d\u7bb1\u5b50\u0036"}.size().(#this>0?#this*10:0),throwExp}' '#cost>200&&params[0].clientIp=="10.30.50.39"&&returnObj.content.size()>0'  -n 5  -x 3

ognl是从左向右执行,把左边的结果作为右边的入参继续执行,直到最终。
注意:如果ognl表达式中有中文,需要转为unicode才能正常筛选。
(#this>0?#this*10:0) 子表达式

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值