前言
初识Arthas,是为了排查项目的JVM内存溢出问题,后发现在线上排查问题及性能调优时,也有不错的妙用。 虽有官方文档,在这里做下笔记加深使用印象,我这里只介绍相对实用的操作指令
使用经验:
- jvm 内存占比及回收状态,适当帮助调整JVM参数---- dashboard
- 当需要加日志排查问题时,线上一般会考虑 watch 或 trace 指令查看方法的入参和出参协助排查是否业务方问题(敏感日志或方法调用量超大不方面埋点时)
- 线上主机CPU占比过高问题排查 + 性能调优----火焰图
- 在不重启应用情况下,手动修改日志打印权限,查看线上执行细节问题 ---- logger
- 在不重启应用情况下,动态修改线上的代码,并使其生效
安装&启动
-
安装
-
启动
java -jar arthas-boot.jar
备注: 需跟微服务进程同一个用户启动,选择需要监控的微服务进程 例如arthas-demo启动使用root用户,则使用root用户启动arthas-boot.jar
常规操作
常用指令
cls
类似linux的 clear ,清空界面内容
ctrl + c / quit / exit:
退出当前连接,类似 linux的 ctrl + z
ctrl + z / stop
退出arthas操作界面,重回linux界面
tab
补全arthas指令
arthas 进阶
dashboard
主要功能:
看当前活跃线程(ID/GOURP/NAME)cpu 使用占比
查看GC回收次数及jvm内存使用情况
- ID: Java 级别的线程 ID
- NAME: 线程名
- GROUP: 线程组名
- PRIORITY: 线程优先级, 1~10 之间的数字,越大表示优先级越高
- STATE: 线程的状态
- CPU%: 线程的 cpu 使用率。比如采样间隔 1000ms,某个线程的增量 cpu 时间为 100ms,则 cpu 使用率=100/1000=10%
- DELTA_TIME: 上次采样之后线程运行增量 CPU 时间,数据格式为秒
- TIME: 线程运行总 CPU 时间,数据格式为分:秒
- INTERRUPTED: 线程当前的中断位状态
- DAEMON: 是否是 daemon 线程
- JVM 内部线程
- Memory 可查看内存使用状态,Eden区、新生代/老年代 使用内存占比 ,内存回收次数等
heapdump
功能:jmap中的heap dump功能
例:dump到指定文件:
- heapdump /opt/hihonor/example.hprof
jvm
功能:查看当前微服务jvm输入参数信息,jvm使用占比,线程总共开启数量,活跃线程数量,类加载数量,是否有死锁线程,jvm最大可以打开的文件描述符数,和当前已打开的描述符数。 个人觉得功能跟dashboard 相似
logger
功能:查看 logback-spring.xml 的日志配置和动态修改日志级别
查看配置
- logger
修改日志级别
- logger -c {hashCode} --name {name} --level {level}
- logger --classLoaderClass {classLoader} --name {name} --level {level}
加载类hash值获取:
-
sc -d className 查看类加载器的hashCode编码(微服务每次启动,hashcode是动态变化的)
将Mylogger日志级别调成debug ,查看线上更明细日志 logger --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader --name com.example.arthastest.support.Mylogger --level debug 恢复 info 级别 logger -c 4b9e13df --name com.example.arthastest.support.Mylogger --level info
thread
查看当前最忙的3个线程,并打印出堆栈和CPU占比
- thread -n 3
笔者demo过于简单,请忽略
jad
反编译class生成java文件使用,可以验证代码是否成功部署到某个环境 jad一般和mc及retransform搭配使用
- jad --source-only className
- jad className
mc
编译java代码使用,如果是编译jad反编译的java代码,切记一定要带 hashcode或类加载器
- mc -c {hashcode} com.example.arthastest.controller.ArthasController
- mc --classLoaderClass {ClassLoader} com.example.arthastest.controller.ArthasController
retransform
重置线上class
动态修改class生效限制
- 不允许新增类属性和方法
- 方法如果退不出来,即方法内有死循环时,改动不生效(仅限本栈帧的死循环,调用的其他方法不受影响)
-
retransform /opt/myapp/apps/arthas-demo/com/example/arthastest/controller/ArthasController.class
-
retrasform -l 呈现已修改的类信息
-
retransform -d id 还原已修改的类信息,但还要重置retransform才行
动态修改线上应用字节码文件,并使之生效 - jad 命令反编译,然后可以用其它编译器,比如 vim 来修改源码 - mc 命令来内存编译修改过的代码 - 用 retransform 命令加载新的字节码 第一和第二步,可以通过本地上传class文件实现
动态修改流程参照截图:
1. jad命令线上生成java代码,一定要携带 --source-only 参数
jad --source-only com.example.arthastest.controller.ArthasController > /opt/myapp/ArthasController.java
2. 第一步修改java源码完成后,重新编译,此时切记带上加载类参数(第一步生成的java代码已有该行,可复制)
mc --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader /opt/myapp/ArthasController.java
3. 重置字节码,使其生效
retransform /opt/myapp/apps/arthas-demo/com/example/arthastest/controller/ArthasController.class
stack/trace/watch/
三者都和方法调用链相关,放在一起。 watch 命令我个人很喜欢使用,查看线上方法是否生效,是否正常被调用
- stack :方法是否被执行,被哪个方法执行,打印方法执行的堆栈信息
- trace :追踪方法调用链,统计整个方法调用链的性能开销 以上指令两者调用相似 stack/trace {className} {methodName}
trace
stack
-
watch :查看方法被调用时的入参、出参,是否抛出异常
-
watch {className} {methodName} {params,returnObj} -x 2
一般我会搭配管道 grep 使用
入参出参都在 result 参数内,排序 params->target->returnObj ,一般target用不到, 已过滤。 ognl 条件表达式我很少用,有兴趣的同学可以研究下,可以过滤出我们想要的结果
profiler
生成火焰图,性能调优神器,不用过多介绍了
- profiler start --开始
- profiler stop -- 结束,结束后会生成该期间内统计的各方法性能时长火焰图
以上是我个人觉得需要掌握的常用指令,如还有其他实操常用指令,欢迎留言。