Arthas学习笔记

Arthas诊断工具手册

1.安装

#使用arthas-boot(推荐)
下载arthas-boot.jar,然后用java -jar的方式启动:
curl -O https://arthas.aliyun.com/arthas-boot.jar

#卸载:
#在 Linux/Unix/Mac平台删除下面文件:
rm -rf ~/.arthas/
rm -rf ~/logs/arthas
#Windows平台直接删除user home下面的.arthas和logs/arthas目录

2.启停arthas

#启动命令
java -jar arthas-boot.jar
#选择应用java进程,端口被占用则可指定端口启动
java -jar arthas-boot.jar --telnet-port 9998 --http-port -1
#选择之后,Arthas会attach到目标进程上,并输出日志

###退出arthas
#如果只是退出当前的连接,可以用quit或者exit命令。Attach到目标进程上的arthas还会继续运行,端口会保持开放,下次连接时可以直接连接上。
#如果想完全退出arthas,可以执行stop命令。

3.Docker Arthas

#使用有JDK的镜像,例如
FROM openjdk:8-jdk

1.删除本地已有的math-game docker container(非必要)
$ docker stop math-game || true && docker rm math-game || true
2.启动math-game demo应用
$ docker run --name math-game -it hengyunabc/arthas:latest /bin/sh -c "java -jar /opt/arthas/math-game.jar"
3.启动arthas-boot来进行诊断
$ docker exec -it math-game /bin/sh -c "java -jar /opt/arthas/arthas-boot.jar"
4.诊断Docker里的Java进程
docker exec -it  ${containerId} /bin/bash -c "wget https://arthas.aliyun.com/arthas-boot.jar && java -jar arthas-boot.jar"
4.1 诊断k8s里容器里的Java进程
kubectl exec -it ${pod} --container ${containerId} -- /bin/bash -c "wget https://arthas.aliyun.com/arthas-boot.jar && java -jar arthas-boot.jar"
5.把Arthas安装到基础镜像里,可以很简单把Arthas安装到你的Docker镜像里。
FROM openjdk:8-jdk-alpine
# copy arthas
COPY --from=hengyunabc/arthas:latest /opt/arthas /opt/arthas

4.常见问题

1.com.sun.tools.attach.AttachNotSupportedException: Unable to open socket file: target process not responding or HotSpot VM not loaded
答:检查当前用户和目标java进程是否一致。如果不一致,则切换到同一用户。JVM只能attach同样用户下的java 进程。
尝试使用 jstack -l $pid,如果进程没有反应,则说明进程可能假死,无法响应JVM attach信号。所以同样基于attach机制的Arthas无法工作。尝试使用jmap heapdump后分析
2.怎么watch、trace 构造函数 ?
watch demo.MathGame <init> '{params,returnObj,throwExp}' -v
3.方法同名过滤
同名方法过滤可以通过匹配表达式,可以使用表达式核心变量中所有变量作为已知条件,可以通过判断参数个数params.length ==1, 参数类型params[0] instanceof java.lang.Integer、返回值类型 returnObj instanceof java.util.List 等等一种或者多种组合进行过滤。
watch demo.MathGame primeFactors '{params,returnObj,throwExp}' 'params.length >0 && returnObj instanceof java.util.List' -v

5.OGNL表达式

#OGNL表达式介绍:
OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,他是一个开源项目。Struts框架使用OGNL作为默认的表达式语言
#OGNL优势
1.支持对象方法调用,如:×××.doSomeSpecial();
2.支持类静态的方法调用和值访问,表达式的格式
@[类全名(包括包路径)]@[方法名 |  值名],例如:
@java.lang.String@format('foo %s', 'bar')
或@tutorial.MyConstant@APP_NAME;
3.支持赋值操作和表达式串联,
如price=100, discount=0.8,calculatePrice(),这个表达式会返回80;
4.访问OGNL上下文(OGNL context)和ActionContext;
5.操作(创建)集合对象。

#OGNL用法
1.调用静态属性
ognl '@全路径类目@静态属性名'
2.调用静态方法
ognl '@全路径类目@静态方法名("参数")'
例:-X 2 表示显示的深度,
ognl '@com.shirc.arthasexample.ognl.OgnlTest@getPerson("src",18)' -X 2
3.方法A的返回值当做方法B的入参,并返回一个list
ognl '#value1=@com.shirc.arthasexample.ognl.OgnlTest@getPerson("src",18), #value2=@com.shirc.arthasexample.ognl.OgnlTest@setPerson(#value1) ,{#value1,#value2}' -x 2
4.方法入参是简单类型列表
ognl '@com.shirc.arthxample.ognl.OgnlTest@getChilds({"jinjidelaomanong","jjdlmn"})' -x 2
5.方法入参是一个复杂对象
ognl '#obj=new com.shirc.arthasexample.ognl.Shirc("jjdlmn",true),@com.shirc.arthasexample.ognl.OgnlTest@inputObj(#obj)' -x 2
6.访问复杂对象属性
ognl '@com.shirc.arthasexample.ognl.OgnlTest@getPerson("src",18).name' -x 4
7.访问List或者数组类型
ognl '@com.shirc.arthasexample.ognl.OgnlTest@getChilds({"jinjidelaomanong","jjdlmn"})[0]' -x 2
8. 访问Map对象
ognl '@com.shirc.arthasexample.ognl.OgnlTest@getMap()["shirc"]' -x 2
ognl '@com.shirc.arthasexample.ognl.OgnlTest@getMap()["shirc"].sex' -x 2
shirc: 是map的key; 记得要用双引号"" 引起来
9.#变量引用 #this 当前对象
ognl '@com.shirc.arthasexample.ognl.OgnlTest@getMap()["shirc"].(#this.sex=="boy"?"BoyNB":"GirlNB")' -x 2
10.调用构造方法
new 全路径类名()
ognl 'new com.shirc.arthasexample.ognl.Shirc("shirc",true)'

6.常用命令

1.基础命令

#help——查看命令帮助信息
#session——查看当前会话的信息
#cat——打印文件内容,和linux里的cat命令类似
#echo–打印参数,和linux里的echo命令类似
#grep——匹配查找,和linux里的grep命令类似
#reset——重置增强类,将被 Arthas 增强过的类全部还原,Arthas 服务端关闭时会重置所有增强过的类
#history——打印命令历史
#quit/exit——退出当前 Arthas 客户端,其他 Arthas 客户端不受影响
#stop——关闭 Arthas 服务端,所有 Arthas 客户端全部退出
#pwd——返回当前的工作目录,和linux命令类似
#cls——清空当前屏幕区域
#tee——复制标准输入到标准输出和指定的文件,和linux里的tee命令类似
#version——输出当前目标 Java 进程所加载的 Arthas 版本号
#keymap——Arthas快捷键列表及自定义快捷键
#base64——base64编码转换,和linux里的base64命令类似

2.jvm相关

#dashboard——当前系统的实时数据面板 
-i 刷新实时数据的时间间隔 (ms),默认5000ms
-n 刷新实时数据的次数
#thread——查看当前 JVM 的线程堆栈信息
id	线程id
-n 	指定最忙的前N个线程并打印堆栈
-b	找出当前阻塞其他线程的线程
-i 	指定cpu使用率统计的采样间隔,单位为毫秒,默认值为200
--all	显示所有匹配的线程
#jvm——查看当前 JVM 的信息
1.THREAD相关
COUNT: JVM当前活跃的线程数
DAEMON-COUNT: JVM当前活跃的守护线程数
PEAK-COUNT: 从JVM启动开始曾经活着的最大线程数
STARTED-COUNT: 从JVM启动开始总共启动过的线程次数
DEADLOCK-COUNT: JVM当前死锁的线程数
2.文件描述符相关
MAX-FILE-DESCRIPTOR-COUNT:JVM进程最大可以打开的文件描述符数
OPEN-FILE-DESCRIPTOR-COUNT:JVM当前打开的文件描述符数
#sysprop——查看和修改JVM的系统属性
sysprop java.version 查看单个属性
sysprop user.country CN 修改单个属性
#sysenv——查看JVM的环境变量
sysenv USER 查看单个属性
#ognl——执行ognl表达式
express	执行的表达式
-c 	执行表达式的 ClassLoader 的 hashcode,默认值是SystemClassLoader
需要使用classload获取hashcode,因为hashcode是变化的
--classLoaderClass 唯一实例全类名 	指定执行表达式的 ClassLoader 的 class name
-x 	结果对象的展开层次,默认值1
#vmoption——查看和修改JVM里诊断相关的option
vmoption PrintGC 查看一个
vmoption PrintGC true 修改
#perfcounter——查看当前 JVM 的Perf Counter信息
可以用-d参数打印更多信息
#logger——查看和修改logger
logger -n org.springframework.web 查看指定名字的logger信息
logger -c 2a139a55 需要先获取hashcode
logger -c 2a139a55 --name ROOT --level debug 修改ROOT的日志级别
--include-no-appender logger命令只打印有appender的logger的信息。如果想查看没有appender的logger的信息,可以加上参数
#heapdump——dump java heap, 类似jmap命令的heap dump功能
heapdump --live /tmp/dump.hprof 只dump live对象到指定文件
#vmtool——从jvm里查询对象,执行forceGc
获取对象 --limit 默认是10
vmtool --action getInstances --className java.lang.String --limit 10
强制GC
vmtool --action forceGc
#getstatic——查看类的静态属性
#mbean——查看 Mbean 的信息

3.class/classloader相关

#sc——Search-Class查看JVM已加载的类信息
class-pattern	类名表达式匹配
method-pattern	方法名表达式匹配
-d	输出当前类的详细信息,包括这个类所加载的原始文件来源、类的声明、加载的ClassLoader等详细信息。如果一个类被多个ClassLoader所加载,则会出现多次
-E	开启正则表达式匹配,默认为通配符匹配
-f	输出当前类的成员变量信息(需要配合参数-d一起使用)
-x	指定输出静态变量时属性的遍历深度,默认为 0,即直接使用 toString 输出
-c	指定class的 ClassLoader 的 hashcode
--classLoaderClass	指定执行表达式的 ClassLoader 的 class name
-n	具有详细信息的匹配类的最大数量(默认为100)
#sm——Search-Method查看已加载类的方法信息
用法除了没有 -f -x和sc命令无区别
#jad——反编译指定已加载类的源码
class-pattern	类名表达式匹配
-c	类所属 ClassLoader 的 hashcode
--classLoaderClass	指定执行表达式的 ClassLoader 的 class name
-E	开启正则表达式匹配,默认为通配符匹配
#mc——Memory Compiler/内存编译器,内存编译.java文件为.class文件
-c  参数指定classloader
--classLoaderClass  参数指定ClassLoader
-d  命令指定输出目录 mc -d /tmp/output /tmp/ClassA.java /tmp/ClassB.java
#retransform——加载外部的.class文件,retransform到JVM里,一般配合jad/mc使用
retransform /tmp/Test.class
   retransform -l					#查看entity list
   retransform -d 1                    # delete id为1的 retransform entry
   retransform --deleteAll             # delete all retransform entries#Ps:如果不清除掉所有的 retransform entry,并重新触发 retransform ,则arthas stop时,retransform过的类仍然生效。
   retransform --classPattern demo.*   # triger retransform classes#ps:当存在多个 retransform entry时,如果显式触发 retransform ,则最后添加的entry生效(id最大的)。
   retransform -c 327a647b /tmp/Test.class /tmp/Test\$Inner.class
   retransform --classLoaderClass 'sun.misc.Launcher$AppClassLoader' /tmp/Test.class
#redefine——加载外部的.class文件,redefine到JVM里,推荐使用retransform
1.reset命令对redefine的类无效。如果想重置,需要redefine原始的字节码。
2.redefine命令和jad/watch/trace/monitor/tt等命令会冲突。执行完redefine之后,如果再执行上面提到的命令,则会把redefine的字节码重置
#dump——dump JVM中已加载类的字节码文件即Class文件到特定目录
class-pattern	类名表达式匹配
-c	类所属 ClassLoader 的 hashcode
--classLoaderClass	指定执行表达式的 ClassLoader 的 class name
-d	设置类文件的目标目录
-E	开启正则表达式匹配,默认为通配符匹配
#classloader——查看classloader的继承树,urls,类加载信息,使用classloader去getResource
-l	按类加载实例进行统计
-t	打印所有ClassLoader的继承树
-a	列出所有ClassLoader加载的类,请谨慎使用
-c	ClassLoader的hashcode
--classLoaderClass	指定执行表达式的 ClassLoader 的 class name
-c hashcode -r resources	用ClassLoader去查找resource
-c hashcode --load class	用ClassLoader去加载指定的类

4.monitor/watch/trace相关

#在线上、预发使用时,请尽量明确需要观测的类、方法以及条件,诊断结束要执行 stop 或将增强过的类执行 reset 命令。
watch/trace/monitor/stack/tt 命令都支持 --exclude-class-pattern 参数;比如:
watch javax.servlet.Filter * --exclude-class-pattern com.demo.TestFilter
watch/stack/trace这个三个命令都支持#cost
####monitor——方法执行监控
1.参数
class-pattern	类名表达式匹配
method-pattern	方法名表达式匹配
condition-express	条件表达式
-E	开启正则表达式匹配,默认为通配符匹配
-c	统计周期,默认值为120秒
-b	在方法调用之前计算condition-express
2.监控的维度说明
timestamp	时间戳
class	Java类
method	方法(构造方法、普通方法)
total	调用次数
success	成功次数
fail	失败次数
rt	平均RT
fail-rate	失败率

3例:monitor -c 5 demo.MathGame primeFactors "params[0] <= 2"
每5S监视一次方法primeFactors,条件为第一个参数小于2
######watch——方法执行数据观测
class-pattern	类名表达式匹配
method-pattern	方法名表达式匹配
express	观察表达式,默认值:{params, target, returnObj}
condition-express	条件表达式
-b	在方法调用之前观察
-e	在方法异常之后观察
-s	在方法返回之后观察
-f	在方法结束之后(正常返回和异常返回)观察
-E	开启正则表达式匹配,默认为通配符匹配
-x	指定输出结果的属性遍历深度,默认为 1
例:观察耗时超过200ms的MathGame的primeFactors方法的参数和返回list
watch demo.MathGame primeFactors '{params, returnObj}' '#cost>200' -x 2
#######trace——方法内部调用路径,并输出方法路径上的每个节点上耗时
class-pattern	类名表达式匹配
method-pattern	方法名表达式匹配
condition-express	条件表达式
-E	开启正则表达式匹配,默认为通配符匹配
-n	命令执行次数
 #cost	方法执行耗时
#默认情况下,trace不会包含jdk里的函数调用,如果希望trace jdk里的函数,需要显式设置
--skipJDKMethod false  
  
############stack——输出当前方法被调用的调用路径
class-pattern	类名表达式匹配
method-pattern	方法名表达式匹配
condition-express	条件表达式
-E	开启正则表达式匹配,默认为通配符匹配
-n	执行次数限制

###############  tt——TimeTunnel方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测##########
1.参数:
-t  希望记录下类 *Test 的 print方法的每次执行情况。
-n 3 指定需要记录的次数
2.结果显示
INDEX	时间片段记录编号,每一个编号代表着一次调用,后续tt还有很多命令都是基于此编号指定记录操作,非常重要。
TIMESTAMP	方法执行的本机时间,记录了这个时间片段所发生的本机时间
COST(ms)	方法执行的耗时
IS-RET	方法是否以正常返回的形式结束
IS-EXP	方法是否以抛异常的形式结束
OBJECT	执行对象的hashCode(),注意,曾经有人误认为是对象在JVM中的内存地址,但很遗憾他不是。但他能帮助你简单的标记当前执行方法的类实体
CLASS	执行的类名
METHOD	执行的方法名
3.条件表达式
解决方法重载
tt -t *Test print params.length==1
通过制定参数个数的形式解决不同的方法签名,如果参数个数一样,你还可以这样写
tt -t *Test print 'params[1] instanceof Integer'
解决指定参数
tt -t *Test print params[0].mobile=="13989838402"
4.tt -l 查看调用记录  -s 'method.name=="primeFactors"'过滤primeFactors方法的调用记录
5.tt -i index 查看index为index值的调用信息
6.重做一次调用:
tt -i 1004 -p
--replay-times 指定 调用次数,通过 
--replay-interval 指定多次调用间隔(单位ms, 默认1000ms)
7.观察表达式
-w, --watch-express 观察时空隧道使用ognl 表达式
例如:获取类的静态字段、调用类的静态方法
tt -w '@demo.MathGame@random.nextInt(100)'  -x 1 -i 1000

5.profiler火焰图

#profiler 命令支持生成应用热点的火焰图。本质上是通过不断的采样,然后把收集到的采样结果生成火焰图。
profiler 命令基本运行结构是 profiler action [actionArg]

1.启动profiler  默认情况下,生成的是cpu的火焰图,即event为cpu。可以用--event参数来指定
$ profiler start
Started [cpu] profiling

2.获取已采集的sample的数量
$ profiler getSamples
23

3.查看profiler状态
$ profiler status
[cpu] profiling is running for 4 seconds

4.停止profiler
生成html格式结果
默认情况下,结果文件是html格式,也可以用--format参数指定:或者在--file参数里用文件名指名格式。比如--file /tmp/result.html 
$ profiler stop --format html
profiler output file: /tmp/test/arthas-output/20211207-111550.html
OK

5.恢复采样
$ profiler resume
Started [cpu] profiling
start和resume的区别是:start是新开始采样,resume会保留上次stop时的数据。
通过执行profiler getSamples可以查看samples的数量来验证。

6.使用execute来执行复杂的命令
比如开始采样:
profiler execute 'start,framebuf=5000000'
停止采样,并保存到指定文件里:
profiler execute 'stop,file=/tmp/result.html'

7.查看所有支持的action
$ profiler actions
Supported Actions: [resume, dumpCollapsed, getSamples, start, list, execute, version, stop, load, dumpFlat, actions, dumpTraces, status]

8.指定执行时间
比如,希望profiler执行 300 秒自动结束,可以用 -d/--duration 参数指定:
profiler start --duration 300

9.配置 include/exclude来过滤数据,include/exclude 都支持设置多个值 ,但是需要配置在命令行的最后;比如
profiler start --include 'java/*' --include 'demo/*' --exclude '*Unsafe.park*'

9.在linux下面支持的event
$ profiler list
Basic events:
  cpu
  alloc
  lock
  wall
  itimer
Perf events:
  page-faults
  context-switches
  cycles
  instructions
  cache-references
  cache-misses
  branches
  branch-misses
  bus-cycles
  L1-dcache-load-misses
  LLC-load-misses
  dTLB-load-misses
  mem:breakpoint
  trace:tracepoint
参数名称参数说明
action要执行的操作
actionArg属性名模式
[i:]采样间隔(单位:ns)(默认值:10’000’000,即10 ms)
[f:]将输出转储到指定路径
[d:]运行评测指定秒
[e:]要跟踪哪个事件(cpu, alloc, lock, cache-misses等),默认是cpu

6.options

#options json-format 获取单个值
#options save-result true 设置某个值
名称默认值描述
unsafefalse是否支持对系统级别的类进行增强,打开该开关可能导致把JVM搞挂,请慎重选择!
dumpfalse是否支持被增强了的类dump到外部文件中,如果打开开关,class文件会被dump到/${application working dir}/arthas-class-dump/目录下,具体位置详见控制台输出
batch-re-transformtrue是否支持批量对匹配到的类执行retransform操作
json-formatfalse是否支持json化的输出
disable-sub-classfalse是否禁用子类匹配,默认在匹配目标类的时候会默认匹配到其子类,如果想精确匹配,可以关闭此开关
support-default-methodtrue是否支持匹配到default method,默认会查找interface,匹配里面的default method。参考 #1105
save-resultfalse是否打开执行结果存日志功能,打开之后所有命令的运行结果都将保存到~/logs/arthas-cache/result.log
job-timeout1d异步后台任务的默认超时时间,超过这个时间,任务自动停止;比如设置 1d, 2h, 3m, 25s,分别代表天、小时、分、秒
print-parent-fieldstrue是否打印在parent class里的filed

7.用户实战

1.heapdump 下载dump文件,然后使用jprofiler或mat工具分析文件

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

没有什么是应该

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值