线上故障排查工具-arthas
线上故障排查工具-arthas(阿里开源)
阿尔萨斯(arthas)
1.简介
Arthas 是一款线上监控诊断产品,通过全局视角实时查看应用 load、内存、gc、线程的状态信息,并能在不修改应用代码的情况下,对业务问题进行诊断,包括查看方法调用的出入参、异常,监测方法执行耗时,类加载信息等,大大提升线上问题排查效率。
2.背景
通常,本地开发环境无法访问生产环境。如果在生产环境中遇到问题,则无法使用 IDE 远程调试。更糟糕的是,在生产环境中调试是不可接受的,因为它会暂停所有线程,导致服务暂停。
开发人员可以尝试在测试环境或者预发环境中复现生产环境中的问题。但是,某些问题无法在不同的环境中轻松复现,甚至在重新启动后就消失了。
如果您正在考虑在代码中添加一些日志以帮助解决问题,您将必须经历以下阶段:测试、预发,然后生产。这种方法效率低下,更糟糕的是,该问题可能无法解决,因为一旦 JVM 重新启动,它可能无法复现,如上文所述。
Arthas 旨在解决这些问题。开发人员可以在线解决生产问题。无需 JVM 重启,无需代码更改。 Arthas 作为观察者永远不会暂停正在运行的线程。
3.arthas能做什么?
Arthas
是 Alibaba 开源的 Java 诊断工具,深受开发者喜爱。
当你遇到以下类似问题而束手无策时,Arthas
可以帮助你解决:
- 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
- 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
- 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
- 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
- 是否有一个全局视角来查看系统的运行状况?
- 有什么办法可以监控到 JVM 的实时运行状态?
- 怎么快速定位应用的热点,生成火焰图?
- 怎样直接从 JVM 内查找某个类的实例?
Arthas
支持 JDK 6+,支持 Linux/Mac/Windows,采用命令行交互模式,同时提供丰富的 Tab
自动补全功能,进一步方便进行问题的定位和诊断。
4.安装
curl -O https://arthas.aliyun.com/arthas-boot.jar //下载
java -jar arthas-boot.jar //启动
下完以后可以发现这个目录下面有一个jar包。这个jar包就是一个可以执行的jar包,它在执行的时候有个特点,它会检测本地是否有启动的java进程,如果没有启动的java进程,那这个jar包是不能够运行的。
访问 WebConsole
attach 成功后可以打开谷歌浏览器输入http://127.0.0.1:3658/
打开 WebConsole
卸载
rm -rf ./arthas # 隐藏目录
rm -rf logs/ # 日志目录
5.核心监测功能
1、monitor
:监控方法的执行情况
监控指定类中方法的执行情况
用来监视一个时间段中指定方法的执行次数,成功次数,失败次数,耗时等这些信息
参数说明
参数名称 | 参数说明 |
---|---|
class-pathern | 类名表达式匹配 |
method-pattern | 方法名表达式匹配 |
[E] | 开启正则表达式匹配,默认为通配符匹配 |
[c:] | 统计周期,默认值为120秒 |
示例:监控com.example.controler.OrderController类
monitor com.example.controler.OrderController createOrder -c 5
监控的维度说明
监控项 | 说明 |
---|---|
timestamp | 时间戳 |
class | Java类 |
method | 方法(构造方法、普通方法) |
total | 调用次数 |
success | 成功次数 |
fail | 失败次数 |
rt | 平均耗时 |
fail-rate | 失败率 |
2、watch
:检测函数返回值
方法执行数据观测,让你能方便的观察到指定方法的调用情况。
能观察到的范围为:返回值、抛出异常、入参,通过编写OGNL 表达式进行对应变量的查看
参数说明:
watch 的参数比较多,主要是因为它能在 4 个不同的场景观察对象
参数名称 | 参数说明 |
---|---|
class-pattern | 类名表达式匹配 |
method-pattern | 方法名表达式匹配 |
express | 观察表达式 |
condition-express | 条件表达式 |
[b] | 在方法调用之前观察before |
[e] | 在方法异常之后观察 exception |
[s] | 在方法返回之后观察 success |
[f] | 在方法结束之后(正常返回和异常返回)观察 finish |
[E] | 开启正则表达式匹配,默认为通配符匹配 |
[x:] | 指定输出结果的属性遍历深度,默认为 1 |
这里重点要说明的是观察表达式,观察表达式的构成主要由ognl 表达式组成,所以你可以这样写"{params,returnObj}",只要是一个合法的 ognl 表达式,都能被正常支持。
特别说明
- watch 命令定义了4个观察事件点,即 -b 方法调用前,-e 方法异常后,-s 方法返回后,-f 方法结束后
- 4个观察事件点 -b、-e、-s 默认关闭,-f 默认打开,当指定观察点被打开后,在相应事件点会对观察表达式进行求值并输出
- 这里要注意方法入参和方法出参的区别,有可能在中间被修改导致前后不一致,除了 -b 事件点 params 代表方法入参外,其余事件都代表方法出参
- 当使用 -b 时,由于观察事件点是在方法调用前,此时返回值或异常均不存在
- 通过watch命令可以查看函数的参数/返回值/异常信息。
watch com.example.service.impl.OrderServiceImpl createOrder "{params,returnObj}" -X 2
# -b 方法执行前的参数
watch demo.MathGame primeFactors "{params,returnObj}" -x 2 -b
# 查看方法中的属性
watch demo.MathGame primeFactors "{target}" -x 2 -b
查看某一个属性的值
watch demo.MathGame primeFactors "{target.illegalArgumentCount}" -x 2 -b
检测方法在执行前-b、执行后-s的入参params、属性target和返回值returnObj
watch demo.MathGame primeFactors "{params,target,returnObj}" -x 2 -b -s -n 2
输入参数小于0的情况
watch demo.MathGame primeFactors "{params[0],target}" "params[0]<0"
3、trace:根据路径追踪,并记录消耗时间
对方法内部调用路径进行追踪,并输出方法路径上的每个节点上耗时。
简介:
trace 命令能主动搜索 class-pattern/method-pattern 对应的方法调用路径,渲染和统计整个调用链路上的所有性能开销和追踪调用链路。
观察表达式的构成主要由ognl 表达式组成,所以你可以这样写"{params,returnObj}",只要是一个合法的 ognl 表达式,都能被正常支持。
很多时候我们只想看到某个方法的rt大于某个时间之后的trace结果,现在Arthas可以按照方法执行的耗时来进行过滤了,例如trace *StringUtils isBlank '#cost>100'表示当执行时间超过100ms的时候,才会输出trace的结果。
watch/stack/trace这个三个命令都支持#cost耗时条件过滤。
参数说明:
参数名称 | 参数说明 |
---|---|
class-pattern | 类名表达匹配 |
method-pattern | 方法名表达式匹配 |
condition-express | 条件表达式,使用OGNL表达式 |
[E] | 开启正则表达式匹配,默认是通配符匹配 |
[n:] | 设置命令执行次数 |
#cost | 方法执行耗时,单位是毫秒 |
参数名称 | 参数说明 |
---|---|
class-pattern | 类名表达式匹配 |
method-pattern | 方法名表达式匹配 |
condition-express | 条件表达式 |
#cost | 过滤条件,只追踪满足的耗时方法 |
trace com.example.service.impl.OrderServiceImpl createOrder
# 执行一次退出
trace com.example.service.impl.OrderServiceImpl createOrder -n 1
# 默认情况下,trace不会包含jdk里的函数调用,如果希望trace jdk里的函数。
# 需要显式设置--skipJDKMethod false。
trace --skipJDKMethod false demo.MathGame run
# 据调用耗时过滤,trace大于0.5ms的调用路径
trace demo.MathGame run '#cost > 1'
4、stack:输出当前方法被调用的调用路径
输出当前方法被调用的调用路径
很多时候我们都知道一个方法被执行,但这个方法被执行的路径非常多,或者你根本就不知道这个方法是从那里被执行了,此时你需要的是 stack 命令。
参数说明
参数名称 | 参数说明 |
---|---|
class-pattern | 类名表达式匹配 |
method-pattern | 方法名表达式匹配 |
condition-express | 条件表达式,OGNL |
[E] | 开启正则表达式匹配,默认为通配符匹配 |
[n:] | 执行次数限制 |
# 获取primeFactors的调用路径
stack demo.MathGame primeFactors
# 条件表达式来过滤,第0个参数的值小于0,-n表示获取2次
stack demo.MathGame primeFactors 'params[0]<0' -n 2
# 据执行时间来过滤,耗时大于0.5毫秒
stack demo.MathGame primeFactors '#cost>0.5'
5、tt:时间隧道,记录多个请求
time-tunnel 时间隧道。
记录下指定方法每次调用的入参和返回信息,并能对这些不同时间下调用的信息进行观测
简介:
watch 虽然很方便和灵活,但需要提前想清楚观察表达式的拼写,这对排查问题而言要求太高,因为很多时候我们并不清楚问题出自于何方,只能靠蛛丝马迹进行猜测。
这个时候如果能记录下当时方法调用的所有入参和返回值、抛出的异常会对整个问题的思考与判断非常有帮助。
作用:记录指定方法每次调用的入参和返回值,并后期还可以对这些信息进行观测
参数解析:
tt的参数 | 说明 |
---|---|
-t | 记录某个方法在一个时间段中的调用 |
-l | 显示所有已经记录的列表 |
-n 次数 | 只记录多少次 |
-s 表达式 | 搜索表达式 |
-i 索引号 | 查看指定索引号的详细调用信息 |
-p | 重新调用:指定的索引号时间碎片 |
- -t
tt 命令有很多个主参数,-t 就是其中之一。这个参数表明希望记录下类 *Test 的 print 方法的每次执行情况。
- -n 3
当执行一个调用量不高的方法时可能你还能有足够的时间用 CTRL+C 中断 tt 命令记录的过程,但如果遇到调用量非常大的方法,瞬间就能将你的 JVM 内存撑爆。
此时可以通过 -n 参数指定你需要记录的次数,当达到记录次数时 Arthas 会主动中断tt命令的记录过程,避免人工操作无法停止的情况。
# 最基本的使用来说,就是记录下当前方法的每次调用环境现场。
tt -t demo.MathGame primeFactors
# 需要筛选出 `primeFactors` 方法的调用信息
tt -s 'method.name=="primeFactors"'
# 查看某条记录详细信息
tt -i 1002
字段说明
表格字段 | 字段解释 | |
---|---|---|
INDEX | 时间片段记录编号,每一个编号代表着一次调用,后续tt还有很多命令都是基于此编号指定记录操作,非常重要。 | |
TIMESTAMP | 方法执行的本机时间,记录了这个时间片段所发生的本机时间 | |
COST(ms) | 方法执行的耗时 | |
IS-RET | 方法是否以正常返回的形式结束 | |
IS-EXP | 方法是否以抛异常的形式结束 | |
OBJECT | 执行对象的hashCode() ,注意,曾经有人误认为是对象在JVM中的内存地址,但很遗憾他不是。但他能帮助你简单的标记当前执行方法的类实体 | |
CLASS | 执行的类名 | |
METHOD | 执行的方法名 |
5.1 tt
对重载的支持
# 指定入参的长度=1
tt -t *Test print params.length==1`
# 指定入参的类型
tt -t *Test print 'params[1] instanceof Integer
# 指定固定的入参值
tt -t *Test print params[0].mobile=="13989838402
5.2 tt
发起重新请求
tt 命令由于保存了当时调用的所有现场信息,所以我们可以自己主动对一个 INDEX 编号的时间片自主发起一次调用,从而解放你的沟通成本。此时你需要 -p 参数。通过 --replay-times 指定 调用次数,通过 --replay-interval 指定多次调用间隔(单位ms, 默认1000ms)。
tt -i 1002 -p
# 再重新调用3次
tt -i 1002 -p --replay-interval 3
# 再重新调用3次,并且间隔2S
tt -i 1008 -p --replay-times 3 --replay-interval 2000
6.基础命令
基础命令 | 功能 | |
---|---|---|
1 | help | 显示所有arthas命令,每个命令都可以使用-h的参数,显示它的参数信息 |
2 | cat | 显示文本文件内容 |
3 | grep | 对内容进行过滤,只显示关心的行 |
4 | pwd | 显示当前的工作路径 |
5 | session | 显示当前连接的会话ID |
6 | reset | 重置arthas增强的类 |
7 | version | 显示当前arthas的版本号 |
8 | history | 查看历史命令 |
9 | cls | 清除屏幕 |
10 | quit | 退出当前的会话 |
11 | stop | 结束arthas服务器,退出所有的会话 |
12 | keymap | 显示所有的快捷键 |
1、help
:显示所有的arthas命令及介绍
2、cat
:显示文件下,文本内容
3、grep
: 管道命令
参数列表 | 作用 |
---|---|
-n | 显示行号 |
-i | 忽略大小写查找 |
-m 行数 | 最大显示行数,要与查询字符串一起使用 |
-e “正则表达式” | 使用正则表达式查找 |
4、pwd
:打印当前的工作目录
5、session
:查看当前会话的信息
6、reset
:重置增强后类
重置增强类,将被 Arthas 增强过的类全部还原,Arthas 服务端关闭时会重置所有增强过的类。
reset Test # 还原指定类
reset *List # 还原所有以List结尾的类
reset # 还原所有的类
7、version
:查看当前Arthas
版本
8、history
:查看历史命令
9、quit
:退出Arthas
客户端
exit/quit命令只是退出当前session,arthas server还在目标进程中运行。
想完全退出Arthas,可以执行 stop 命令。
10、stop
:关闭 Arthas 服务端
关闭 Arthas 服务端,所有 Arthas 客户端全部退出
11、keymap
:查看Arthas
快捷键
Arthas快捷键
快捷键说明 | 命令说明 |
---|---|
ctrl + a | 跳到行首 |
ctrl + e | 跳到行尾 |
ctrl + f | 向前移动一个单词 |
ctrl + b | 向后移动一个单词 |
键盘左方向键 | 光标向前移动一个字符 |
键盘右方向键 | 光标向后移动一个字符 |
键盘下方向键 | 下翻显示下一个命令 |
键盘上方向键 | 上翻显示上一个命令 |
ctrl + h | 向后删除一个字符 |
ctrl + shift + / | 向后删除一个字符 |
ctrl + u | 撤销上一个命令,相当于清空当前行 |
ctrl + d | 删除当前光标所在字符 |
ctrl + k | 删除当前光标到行尾的所有字符 |
ctrl + i | 自动补全,相当于敲TAB |
7.Jvm相关命令
jvm相关命令 | 说明 |
---|---|
dashboard | 仪表板,可以显示:线程,内存,堆栈,GC,Runtime等信息 |
thread | 显示线程信息 |
jvm | 与JVM相关的信息 |
sysprop | 显示系统属性信息,也可以修改某个属性 |
sysenv | 查看JVM环境变量的值 |
vmoption | 查看JVM中选项,可以修改 |
getstatic | 获取静态成员变量 |
ognl | 执行一条ognl表达式,对象图导航语言 |
数据说明:
- ID:Java级别的线程ID,注意这个ID不能跟jstack中的nativeID一一对应
- NAME:线程名
- GROUP:线程组名
- PRIORITY:线程优先级, 1~10之间的数字,越大表示优先级越高
- STATE:线程的状态
- CPU%:线程消耗的cpu占比,采样100ms,将所有线程在这100ms内的
- cpu使用量求和,再算出每个线程的cpu使用占比。
- TIME:线程运行总时间,数据格式为分:秒
- INTERRUPTED:线程当前的中断位状态
- DAEMON:是否是daemon线程
2、Thread
:线程相关堆栈信息
参数说明
参数名称 | 参数说明 |
---|---|
数字 | 线程id |
[n:] | 指定最忙的前N个线程并打印堆栈 |
[b] | 找出当前阻塞其他线程的线程 |
[i ] | 指定cpu占比统计的采样间隔,单位为毫秒 |
示例
thread # 显示所有线程的信息
thread 1 # 显示1号线程的运行堆栈
thread -b # 查看阻塞的线程信息
thread -n 3 # 查看最忙的3个线程,并打印堆栈
thread -i 1000 -n 3 # 指定采样时间间隔,每过1000毫秒采样,显示最占时间的3个线程
查看处于等待状态的线程(WAITING、BLOCKED)
thread --state WAITING
3、jvm
THREAD相关
- COUNT:JVM当前活跃的线程数
- DAEMON-COUNT: JVM当前活跃的守护线程数
- PEAK-COUNT:从JVM启动开始曾经活着的最大线程数
- STARTED-COUNT:从JVM启动开始总共启动过的线程次数
- DEADLOCK-COUNT:JVM当前死锁的线程数
4、sysprop
:查看/修改属性
5、sysenv
:查看JVM环境属性
6、vmpotion
:查看JVM中选项
7、getstatic
:获取静态成员变量
8.类和类加载器(class/classLoader)
类,类加载相关的命令 | 说明 |
---|---|
sc | Search Class 查看运行中的类信息 |
sm | Search Method 查看类中方法的信息 |
jad | 反编译字节码为源代码 |
mc | Memory Compile 将源代码编译成字节码 |
redefine | 将编译好的字节码文件加载到jvm中运行 |
1、sc
:查看类信息
参数名称 | 参数说明 |
---|---|
class-pattern | 类名表达式匹配,支持全限定名,如com.taobao.test.AAA,也支持com/taobao/test/AAA这样的格式,这样,我们从异常堆栈里面把类名拷贝过来的时候,不需要在手动把/ 替换为. 啦。 |
method-pattern | 方法名表达式匹配 |
[d] | 输出当前类的详细信息,包括这个类所加载的原始文件来源、类的声明、加载的ClassLoader等详细信息。 如果一个类被多个ClassLoader所加载,则会出现多次 |
[E] | 开启正则表达式匹配,默认为通配符匹配 |
[f] | 输出当前类的成员变量信息(需要配合参数-d一起使用) |
# 模糊搜索,demo包下所有的类
sc demo.*
# 打印类的详细信息
sc -d demo.MathGame
2、sm
:查看已加载方法信息
参数名称 | 参数说明 |
---|---|
class-pattern | 类名表达式匹配 |
method-pattern | 方法名表达式匹配 |
[d] | 展示每个方法的详细信息 |
[E] | 开启正则表达式匹配,默认为通配符匹配 |
# 显示String类加载的方法
sm java.lang.String
# 查看方法信息
sm demo.MathGame
# 查看方法信息(详细信息-d)
sm -d demo.MathGame
3、编译与反编译jad
、mc
、redefine
类相关的命令 | 说明 |
---|---|
jad | 反编译字节码文件得到java的源代码 |
mc | 在内存中将源代码编译成字节码 |
redefine | 将字节码文件重新加载到内存中执行 |
3.1 jad
:反编译已加载类源码
参数名称 | 参数说明 |
---|---|
class-pattern | 类名表达式匹配 |
[E] | 开启正则表达式匹配,默认为通配符匹配 |
# 反编译MathGame方法
jad demo.MathGame
# 反编绎时只显示源代码(排除ClassLoader信息)。
# 默认情况下,反编译结果里会带有ClassLoader信息,通过--source-only选项,可以只打印源代码。方便和mc/redefine命令结合使用。
jad --source-only demo.MathGame
# 反编译到指定文件中
jad --source-only demo.MathGame > Hello.java
# 只反编译mathGame类型中main方法
jad demo.MathGame main
3.2 mc
:编译Java代码
# 在内存中编译Hello.java为Hello.class
mc /root/Hello.java
# 可以通过-d命令指定输出目录
mc -d /root/bbb /root/Hello.java
3.3 redefine
:加载外部.class
文件
加载外部的.class文件,redefine到JVM里
注意, redefine后的原来的类不能恢复,redefine有可能失败(比如增加了新的field)。
reset命令对redefine的类无效。如果想重置,需要redefine原始的字节码。
redefine命令和jad/watch/trace/monitor/tt等命令会冲突。执行完redefine之后,如果再执行上面提到的命令,则会把redefine的字节码重置。
redefine的限制
- 不允许新增加field/method
- 正在跑的函数,没有退出不能生效
1. 使用jad反编译
jad --source-only com.example.service.impl.OrderServiceImpl > d:/arthas/OrderServiceImpl.java
2.按上面的代码编辑完毕以后,使用mc内存中对新的代码编译
mc d:/arthas/OrderServiceImpl.java /root
3.使用redefine命令加载新的字节码
redefine F:\arthas\demo\com\example\service\impl\OrderServiceImpl.class
4、dump
:保存已加载字节码文件到本地
将已加载类的字节码文件保存在特定目录:logs/arthas/classdump
不同的类加载器放在不同的目录下。
dump作用:将正在JVM中运行的程序的字节码文件提取出来,保存在logs相应的目录下
数名称 | 参数说明 |
---|---|
class-pattern | 类名表达式匹配 |
[c:] | 类所属 ClassLoader 的 hashcode |
[E] | 开启正则表达式匹配,默认为通配符匹配 |
dump java.lang.String
# 把demo包下所有的类的字节码文件保存到~/logs/arthas/classdump/目录下
dump demo.*
5、classloader
:获取类加载器的信息
作用:
classloader 命令将 JVM 中所有的classloader的信息统计出来,并可以展示继承树,urls等。
可以让指定的classloader去getResources,打印出所有查找到的resources的url。对于ResourceNotFoundException异常比较有用。
参数名称 | 参数说明 |
---|---|
[l] | 按类加载实例进行统计 |
[t] | 打印所有ClassLoader的继承树 |
[a] | 列出所有ClassLoader加载的类,请谨慎使用 |
[c:] | ClassLoader的hashcode |
[c: r:] | 用ClassLoader去查找resource |
[c: load:] | 用ClassLoader去加载指定的类 |
# 默认按类加载器的类型查看统计信息
classloader
# 按类加载器的实例查看统计信息,可以看到类加载的hashCode
classloader -l
# 查看ClassLoader的继承树
classloader -t
# 通过类加载器的hash,查看此类加载器实际所在的位置
classloader -c 680f2737
# 使用ClassLoader去查找类的class文件所在的位置
classloader -c 680f2737 -r java/lang/String.class
# 使用ClassLoader去加载类
classloader -c 70dea4e --load java.lang.String
classloader命令主要作用有哪些?
- 显示所有类加载器的信息
- 获取某个类加载器所在的jar包
- 获取某个资源在哪个jar包中
- 加载某个类
9、option
全局选项
查看或设置arthas全局环境变量
名称 | 默认值 | 描述 |
---|---|---|
unsafe | false | 是否支持对系统级别的类进行增强,打开该开关可能导致把JVM搞挂,请慎重选择! |
dump | false | 是否支持被增强了的类dump到外部文件中,如果打开开关,class文件会被dump到/${application dir}/arthas-class-dump/ 目录下,具体位置详见控制台输出 |
batch-re-transform | true | 是否支持批量对匹配到的类执行retransform操作 |
json-format | false | 是否支持json化的输出 |
disable-sub-class | false | 是否禁用子类匹配,默认在匹配目标类的时候会默认匹配到其子类,如果想精确匹配,可以关闭此开关 |
debug-for-asm | false | 打印ASM相关的调试信息 |
save-result | false | 是否打开执行结果存日志功能,打开之后所有命令的运行结果都将保存到~/logs/arthas-cache/result.log 中 |
job-timeout | 1d | 异步后台任务的默认超时时间,超过这个时间,任务自动停止;比如设置 1d, 2h, 3m, 25s,分别代表天、小时、分、秒 |
print-parent-fields | true | 是否打印在parent class里的filed |
查看所有option
# 查看默认值
options save-result
# 更新默认值
options save-result true
# 查看更新后值
options save-result
10 profiler
火焰图
profiler 命令支持生成应用热点的火焰图。本质上是通过不断的采样,然后把收集到的采样结果生成火焰图。
profiler | 命令作用 |
---|---|
profiler start | 启动profiler,默认情况下,生成cpu的火焰图 |
profiler list | 显示所有支持的事件 |
profiler getSamples | 获取已采集的sample的数量 |
profiler status | 查看profiler的状态,运行的时间 |
profiler stop | 停止profiler,生成火焰图的结果,指定输出目录和输出格式:svg或html |
启动profiler
profiler start
11.使用
问题1 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?**
这个问题经常在处理依赖冲突的时候会遇到,有一些类的名称完全一样,无法通过常规的办法查看具体从哪个jar包加载。
1.sc
通过sc命令模糊查看当前JVM中是否包含关键字的类,以及获取其完全名称
2.classLoader
通过classLoader命令查看class文件来自哪一个jar包
注意 classloader -c 后面的值填上面第一步中获取到的 Hash 值,class 文件路径使用'/'分割,且必须以.class 结尾。
问题 2:我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
使用 watch 和 tt 命令,非常好用。
这两个命令都是用来查看方法调用过程的,不同的是 watch 命令是调用一次打印一次方法的调用情况,而 tt 命令可以先生成一个不断增加的调用列表,然后指定其中某一项进行观测。
1.使用watch命令查看方法的调用情况
watch com.example.service.impl.OrderServiceImpl handleOrder "{params,target,returnObj}" -f -x 4
watch 后面跟上完全类名和方法名,以及一个 OGNL 的表达式,-f 表示不论正常返回还是异常返回都进行观察,-x 表示输出结果的属性遍历深度,默认为 1,
使用 tt 命令来观测方法调用情况,tt 命令可以查看「多次调用」并选择其中一个进行观测
命令
tt -t com.example.service.impl.OrderServiceImpl handleOrder
TIMESTAMP表示方法调用发生的时间,COST 表示调用耗时(ms),IS-RET表示是否正常返回,IS-EXP 表示是否异常返回,OBJECT 表示对象的 HASH 值
对于具体一个时间片的信息而言,你可以通过 -i 参数后边跟着对应的 INDEX 编号查看到他的详细信息
如何判断代码是否已提交
通过 jad --source-only 可以查看源代码。
问题 3:遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
通过上面问题 2 的 watch 和 tt 命令可以查看方法调用情况。
此外,可以通过 redefine 命令「热替换」线上的代码,需要注意应用重启之后会失效.
问题 4:线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
使用 tt 命令并将命令行返回结果输出到一个文件中,后续可以选择异常的一行记录使用 tt -i 命令进行深入的分析。
tt -t com.example.service.impl.OrderServiceImpl handleOrder | tee D:/arthas/log
tee指令会从标准输入设备读取数据,将其内容输出到标准输出设备,同时保存成文件。
monitor 命令统计方法调用成功失败情况。
命令
monitor -c 10 com.example.service.impl.OrderServiceImpl handleOrder | tee D:/arthas/log1
-c 后面接统计周期,默认值为120秒
问题 5:是否有一个全局视角来查看系统的运行状况?
使用 dashboard 命令可以查看当前系统的实时数据面板
从图中可以看到线程情况,内存使用情况,系统参数等
问题 6:有什么办法可以监控到JVM的实时运行状态?
使用 jvm 命令可以查看 JVM 的实时运行状态。
问题 7:怎么快速定位应用的热点,生成火焰图?
问题 8:怎样直接从JVM内查找某个类的实例?
vmtool
通过 --limit参数,可以限制返回值数量,避免获取超大数据时对JVM造成压力。默认值是10。
如果想精确的定位到具体的类实例,可以通过指定 classloader name 或者 classloader hash
vmtool --classloader 18b4aac2 --action getInstances --className com.example.service.impl.OrderServiceImpl
vmtool进行强制GC
vmtool --action forceGc
案例
package com.example.service.impl;
import com.example.service.OrderServcie;
import org.springframework.stereotype.Service;
@Service
public class OrderServiceImpl implements OrderServcie {
private static String PATH = "/arthas";
@Override
public String createOrder() {
System.out.println("开始执行业务");
handleUser();
handleOrder();
handleStock();
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "订单创建成功";
}
private void handleUser(){
System.out.println("开始处理用户业务");
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("用户业务处理完毕");
}
private void handleOrder(){
System.out.println("开始处理订单业务");
// try {
// Thread.sleep(30000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
System.out.println("订单业务处理完毕");
}
private void handleStock(){
System.out.println("开始处理库存业务");
try {
Thread.sleep(40000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("库存业务处理完毕");
}
}
使用arthas排查过程
1)启动Arthas
2)使用dashboard 命令定位当前的进程的整体情况
3)使用 thread命令查询当前进程情况
通过thread命令列出了该线程中的那个类的哪个方法处理的非常慢,到这里,就大致定位到了问题的接口和方法;
4)使用 trace 命令进一步观察当前的方法调用链路中的各阶段执行耗时情况
在使用trace之后,根据链路中的各个阶段的执行耗时,进一步分析和定位到具体的代码块
watch场景下方法参数及返回值监控
1.观察入参
watch com.example.demo.ThreadTest getResult “{params, returnObj}” -x 2 -b
2.监控异常
watch com.example.demo.ThreadTest timer1 “{params, throwExp}” -e -x 2
3.观察出参及返回值
watch com.example.demo.ThreadTest getResult “{params, returnObj}” -x 2
利用tt命令对偶发异常进行监控
更多推荐
所有评论(0)