Arthas


Arthas

一、Arthas简介

Arthas 官网:https://arthas.aliyun.com/doc/install-detail.html

Arthas-idea-plugin 插件文档:https://www.yuque.com/arthas-idea-plugin/help/pzldzl

Arthas 用户案例:https://github.com/alibaba/arthas/issues?q=label%3Auser-case

二、Arthas火焰图

1.Async-profiler

Async-profiler 说明:https://www.yuque.com/arthas-idea-plugin/help/iisg20

2.启动耗时火焰图

(1)在Idea的Springboot启动主类 VM Options 上添加如下代码:

在应用启动的JVM参数中,添加debugger参数,注意其中的suspend参数需要设为y,表示在debugger连接之前,程序会进行阻塞等待。

-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=10000

(2)新建一个shell窗口启动Arthas

anubis:arthas-packaging-3.7.1-bin/ $ ./as.sh                                                            [10:05:06]
Arthas script version: 3.7.1
[INFO] JAVA_HOME: /Library/Java/JavaVirtualMachines/jdk-1.8.jdk/Contents/Home
Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.
* [1]: 43488
  [2]: 14570
  [3]: 44779 org.jetbrains.jps.cmdline.Launcher
  [4]: 44780 -- main class information unavailable

选择第四个,启动profiler,由于我们需要分析启动过程的耗时阶段,所以我们需要指定跟踪采集的事件为wall

profiler -e wall start

(3)新建一个shell窗口触发程序启动,

利用jdb(jdk自带的debugger工具)连接对应的JVM进程,将此应用run起来。

jdb -attach localhost:10000

连接完成后,执行cont命令,让程序运行起来

cont

(4)程序启动完成后在Arthas的Shell窗口内输入

profiler stop --file /Users/anubis/Downloads/software/arthas-packaging-3.7.1-bin/rcs_start_server.html

三、Arthas常用命令

1.trace

查看方法调用链路以及方法各部分的耗时(配合arthas插件使用)

# java.* 下的函数调用默认会忽略掉。通过增加--skipJDKMethod false参数可以打印出来
# -n 参数指定捕捉结果的次数
trace com.asiainfo.pay.check.analyzer.service.impl.CsvTxtAnalyzerServiceImpl columnMap  -n 5 --skipJDKMethod false 

# -E trace 多个类或者多个函数 '1==1' 表示全部 method1|method2|method3
trace -E com.asiainfo.pay.check.analyzer.service.impl.CsvTxtAnalyzerServiceImpl columnMap -n 5  --skipJDKMethod false '1==1'

2.jad

反编译类/方法

# jad + 类全路径
jad com.tracer.service.impl.CheckServiceImpl 

# jad + 类全路径 + 空格 + 方法名
jad com.tracer.service.impl.CheckServiceImpl checkFileFun

3.retransform

加载外部的.class文件到jvm内

# 查看以及加载的类(显示Id)
retransform -l

# 删除指定加载的类
retransform -d <Id>

# 加载类到JVM(本地编译好后将class文件复制到主机上)
retransform /app/check/arthas-packaging-3.7.1-bin/CheckServiceImpl.class
  • 注意 加载类到JVM,不允许新增加字段和方法。

4.vmoption

查看,更新 VM 诊断相关的参数

[arthas@56963]$ vmoption
 KEY                    VALUE                   ORIGIN                 WRITEABLE
---------------------------------------------------------------------------------------------
 HeapDumpBeforeFullGC   false                   DEFAULT                true [JVM准备Full GC之前,生成堆快照]
 HeapDumpAfterFullGC    false                   DEFAULT                true [JVMFull GC之后,生成堆快照]
 HeapDumpOnOutOfMemory  false                   DEFAULT                true [当JVM遇到内存溢出错误时,是否自动创建堆内存转储]
 Error
 HeapDumpPath                                   DEFAULT                true [堆快照文件保存路径]
 CMSAbortablePrecleanW  100                     DEFAULT                true [在并发标记清除(CMS)收集器中,可中断预清理阶段等待用户线程完成的最长时]
 aitMillis
 CMSWaitDuration        2000                    DEFAULT                true [CMS收集器在执行某些操作前等待其他线程完成的最长时间(毫秒)]
 CMSTriggerInterval     -1                      DEFAULT                true [触发CMS垃圾回收的间隔时间(-1表示使用默认值,由JVM自行决定)]
 PrintGC                false                   DEFAULT                true [控制是否打印GC事件的基本信息]
 PrintGCDetails         true                    MANAGEMENT             true [打印GC的详细信息,包括各代的内存变化等]
 PrintGCDateStamps      false                   DEFAULT                true [在GC日志中包含日期时间戳]
 PrintGCTimeStamps      false                   DEFAULT                true [包含GC发生的时间戳(以毫秒为单位自JVM启动)]
 PrintGCID              false                   DEFAULT                true [是否在日志中包含GC事件的唯一标识符]
 PrintClassHistogramBe  false                   DEFAULT                true [在GC前或特定时刻是否打印类的直方图(即内存占用情况)]
 foreFullGC
 PrintClassHistogramAf  false                   DEFAULT                true [在GC后或特定时刻是否打印类的直方图(即内存占用情况)]
 terFullGC
 PrintClassHistogram    false                   DEFAULT                true [在特定时刻是否打印类的直方图(即内存占用情况)]
 MinHeapFreeRatio       0                       DEFAULT                true [控制堆内存的最小空闲比例]
 MaxHeapFreeRatio       100                     DEFAULT                true [控制堆内存的最大空闲比例]
 PrintConcurrentLocks   false                   DEFAULT                true [在进行垃圾回收时,是否打印持有锁的线程信息,帮助诊断死锁问题]

Arthas:

监控:

# 请注意,这些命令,都通过字节码增强技术来实现的,会在指定类的方法中插入一些切面来实现数据统计和观测,
# 因此在线上、预发使用时,请尽量明确需要观测的类、方法以及条件,诊断结束要执行  stop 或将增强过的类执行 reset 命令。
# 1、quit 退出当前 Arthas 客户端,其他 Arthas 客户端不受影响
# 2、shutdown——关闭 Arthas 服务端,所有 Arthas 客户端全部退出
# 3、stop——和shutdown命令一致

monitor——方法执行监控

watch——方法执行数据观测

trace——方法内部调用路径,并输出方法路径上的每个节点上耗时

stack——输出当前方法被调用的调用路径

tt——方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测

watch:

让你能方便的观察到指定方法的调用情况。
能观察到的范围为:返回值、抛出异常、入参,通过编写 OGNL 表达式进行对应变量的查看。

参数说明:
class-pattern        类名表达式匹配
method-pattern        方法名表达式匹配
express                观察表达式
condition-express    条件表达式
-b                    在方法调用之前观察
-e                    在方法异常之后观察
-s                    在方法返回之后观察
-f                     在方法结束之后(正常返回和异常返回)观察 默认开启
-E                    开启正则表达式匹配,默认为通配符匹配
-x                    指定输出结果的属性遍历深度,默认为 1
-n                     执行的次数

特别说明:
watch 命令定义了4个观察事件点,
即 -b 方法调用前,-e 方法异常后,-s 方法返回后,-f 方法结束后

4个观察事件点 -b、-e、-s 默认关闭,-f 默认打开,
当指定观察点被打开后,在相应事件点会对观察表达式进行求值并输出

这里要注意方法入参和方法出参的区别,有可能在中间被修改导致前后不一致,
除了 -b 事件点 params 代表方法入参外,其余事件都代表方法出参

当使用 -b 时,由于观察事件点是在方法调用前,此时返回值或异常均不存在

-x 代表输出结果的深度 ,默认为 1

使用参考:
常规用法:
watch class method {params,returnObj,throwExp}  -x 1 '#cost>200'
观察表达式 { } 可以包裹结果集 , 分割。输出的表达式变量定义
params 代表参数数组,returnObj 代表返回值,throwExp 代表抛出的异常。
过滤耗时大于200ms的

特殊用法:
1、调用第一个参数的方法或属性
watch class method "{params[0].length()}"  -x 1
如果是列表参数,则可以使用这种方式来获取列表中每个对象的指定属性
watch class method "{params[0].{ #this.length()}}" -x 1

2、按照条件过滤
如果是列表,则会过滤列表中长度大于7的字符串
watch class method "{params[0].{? #this.length() > 7}}" -x 1
watch class method "{params,returnObj,throwExp}" "params[0].length() > 7" -x 1
字符串长度 > 7 才会输出 params[0] 的值


3、过滤后统计
watch class method "{params[0].{? #this.length() > 9}.size()}" -x 1

trace:

trace 命令能主动搜索 class-pattern/method-pattern 对应的方法内部调用路径,
渲染和统计整个调用链路上的所有性能开销和追踪调用链路。

参数说明:
class-pattern         类名表达式匹配
method-pattern         方法名表达式匹配
condition-express     条件表达式
-E                     开启正则表达式匹配,默认为通配符匹配
-n                     命令执行次数
#cost                 方法执行耗时

使用参考:
常规用法:
trace class method '#cost>100' -n 1
过滤大于100ms的调用链,只输出一次

特殊用法:
trace命令只会trace匹配到的函数里的子调用,并不会向下trace多层。
因为trace是代价比较贵的,多层trace可能会导致最终要trace的类和函数非常多。

动态trace:
3.3.0 版本后支持。
打开终端1,trace run函数,可以看到打印出 listenerId: 1:

[arthas@59161]$ trace demo.MathGame run
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 112 ms, listenerId: 1
`---ts=2020-07-09 16:48:11;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@3d4eac69
    `---[1.389634ms] demo.MathGame:run()
        `---[0.123934ms] demo.MathGame:primeFactors() #24 [throws Exception]

现在想要深入子函数primeFactors,可以打开一个新终端2,
使用telnet localhost 3658连接上arthas,
再trace primeFactors时,指定listenerId。
再查看终端1,可以发现trace的结果增加了一层,打印了primeFactors函数里的内容

`---ts=2020-07-09 16:49:29;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@3d4eac69
    `---[0.492551ms] demo.MathGame:run()
        `---[0.113929ms] demo.MathGame:primeFactors() #24 [throws Exception]
            `---[0.061462ms] demo.MathGame:primeFactors()
                `---[0.001018ms] throw:java.lang.IllegalArgumentException() #46

通过指定listenerId的方式动态trace,可以不断深入。
另外 watch/tt/monitor等命令也支持类似的功能。

文章作者: Anubis
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Anubis !
评论
  目录