Arthas(阿尔萨斯)定位线上问题

2023-11-23 01:10

本文主要是介绍Arthas(阿尔萨斯)定位线上问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Arthas 阿尔萨斯使用

  • 参考
  • 实际使用案例
    • 线上安装与挂载
    • 火焰图
    • 查找类、查看类详细信息与反编译代码
    • 查看类中的所有field值
    • thread的各种操作
    • 查看入参、返回值、异常
    • 线上修改代码:jad/mc/redefine/retransform
    • 性能监控
    • dump
    • 找到异常线程并查看堆栈
    • Mbean
  • 案例总结
    • trace查看耗时进行调优
    • Arthas底层实现
    • WeakHashMap死循环引起CPU跑满
    • JDK函数调用查询与后台脚本打印数据
    • ognl表达式筛选并观察输入输出
    • 查看某个Spring引用的具体实现
    • tt获取Spring容器内的bean
    • list出现环导致死循环引发的CPU负载过高
    • 奇怪日志来源定位

参考

官方文档:https://arthas.aliyun.com/doc/
用户案例:https://github.com/alibaba/arthas/issues?q=label%3Auser-case
一图流:https://github.com/alibaba/arthas/issues/1003
IDE插件官方文档:https://www.yuque.com/arthas-idea-plugin/help/pe6i45
一篇很好的总结:https://blog.csdn.net/u013735734/article/details/102930307?utm_source=app&app_version=4.13.0&code=app_1562916241&uLinkId=usr1mkqgl919blen

JVM工具专栏:https://cloud.tencent.com/developer/column/3195/tag-10688
https://www.cnblogs.com/chiangchou/p/jvm-4.html

实际使用案例

基础命令:https://arthas.aliyun.com/doc/advanced-use.html#id2

线上安装与挂载

wget https://alibaba.github.io/arthas/arthas-boot.jar
jps -ml
ps -ef | grep java
java -jar arthas-boot.jar {pid}

火焰图

参考

火焰图基本科普与讲解: https://www.ruanyifeng.com/blog/2017/09/flame-graph.html
定位不同问题的不同类型火焰图 + 安装使用教程:<https://www.infoq.cn/article/a8kmnxdhbwmzxzsytlga >
本机可以随意安装火焰图生成工具。用于线上环境时,需要看线上环境用的火焰图生成工具是什么,生成图示之后传到本机进行分析即可。

profiler start
# 一段时间(>30s)后
profiler stop
exit
wget -O /usr/local/bin/toshelper http://tosv.byted.org/obj/ee-oi-intranet/toshelper && chmod +x /usr/local/bin/toshelper
toshelper /tmp/XXX.svg

查找类、查看类详细信息与反编译代码

参考

# 可以找到需要的类全路径
# -d 输出当前类的详细信息:所加载的原始文件来源、类的声明、
# 加载的ClassLoader(可以看出是哪个组件加载的)等详细信息。
sc -d *DispatcharServlet      # 查看某个方法的信息,如果存在的话 ,不加方法的话查看所有方法
sm org.springframework.web.servlet.DispatcherServlet getHandler # 直接反编译出java 源代码,包含类加载器等额外信息
jad package.XXXService.method 

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
sc -d查看详细类的详细信息
在这里插入图片描述

查看类中的所有field值

sc -d -f class

thread的各种操作

https://blog.csdn.net/u013735734/article/details/102930307?utm_source=app&app_version=4.13.0&code=app_1562916241&uLinkId=usr1mkqgl919blen
4.2节
查看topn的线程 + 具体线程堆栈 + 查看blocking线程、死锁线程 + 查看线程池等实例。

https://arthas.aliyun.com/doc/thread.html

// 查看所有线程信息
thread
// 查看前N线程
thread -n 3// 查看具体线程
thread id
// 找出当前阻塞其他线程的线程
thread -b
// 查看指定状态的线程
thread --state WAITING

查看入参、返回值、异常

https://arthas.aliyun.com/doc/watch.html
支持复杂的设定

# 同时监控入参,返回值,及异常。如果有异常,直接打印出来
watch package.testMethod "{params, returnObj, throwExp}" -e -x 2  

几个watch结合ognl的实例

# 观察CommonTest的test方法
# 输出 入参、返回结果、抛出的异常 —— 输出的内容可以动态调整
# 后面跟着的是 条件表达式,表示耗时超过10ms才输出
# -n 表示只执行一次,-x表示 入参和返回结果的展开层次为5层
watch *.CommonTest test "{params,returnObj,throwExp}" '#cost>10' -x 5 -n 1# 耗时大于10ms并且第一个参数等于1才输出
watch *.CommonTest test "{params,returnObj,throwExp}" '#cost>10 && params[0]==1' -x 5 -n 1# 第一个参数大于1 并且第二个参数等于hello才输出
watch *.CommonTest test "{params,returnObj,throwExp}" 'params[0]>1 && params[1]=="hello"' -x 5 -n 1
# 第一个参数小于5或者第二个参数等于"world"就输出
watch *.CommonTest test "{params,returnObj,throwExp}" 'params[0]<5 || params[1]=="wolrd"' -x 5 -n 1
# 第一个参数的name字段等于world时才输出。
# 由于在方法执行过程中参数的name属性可能发生改变,因此加上-b才能观察到真正的入参
watch -b *.CommonTest test "{params,returnObj,throwExp}" 'params[0].name=="wolrd"' -x 5 -n 1# 由于同时指定了-s和-b,所以方法被调用一次,就会输出2次结果(两个场景分开输出),分别是方法被调用前,和返回之后
# 注意,这里如果-n只设置成1,那么只会输出-b对应的输出,-s对应的输出由于没有次数了就无法输出了
watch *.CommonTest test '{params,returnObj,throwExp}' -x 5 -n 2 -s -b

线上修改代码:jad/mc/redefine/retransform

整体而言,还是使用Spring提供的hot swap更为合适。
https://github.com/alibaba/arthas/issues/537

Arthas: https://github.com/alibaba/arthas
jad命令:https://alibaba.github.io/arthas/jad.html
mc命令:https://alibaba.github.io/arthas/mc.html
redefine命令:https://alibaba.github.io/arthas/redefine.html
retransform:https://arthas.aliyun.com/doc/retransform.html

# 先反编译出class源码
jad --source-only com.example.demo.arthas.user.UserController > /tmp/UserController.java  # 然后使用外部工具编辑内容
vim /tmp/UserController.java# 查找加载UserController的ClassLoader
sc -d *UserController | grep classLoaderHash#output : classLoaderHash   1be6f5c3# 再编译成class,只需指明目录即可# 有时候mc命令不一定成功,尤其是很复杂的类有着各种注入各种依赖。
mc -c 1be6f5c3 /tmp/UserController.java -d /tmp # 最后,重新载入定义的类
redefine /tmp/com/example/demo/arthas/user/UserController.class
retransform /tmp/Test.class

更好的做法:
直接在IDE上完成class的编辑,然后去生产环境中将代码拷贝进去,运行redefine命令即可。
https://blog.csdn.net/javageektech/article/details/101443191
注意:

  1. redefine的class不能修改、添加、删除类的field和method,包括方法参数、方法名称及返回值
  2. 如果mc失败,可以在本地开发环境编译好class文件,上传到目标系统,使用redefine热加载class
  3. 目前redefine 和watch/trace/jad/tt等命令冲突,
  4. redefine后的原来的类不能恢复,redefine有可能失败

retransform直接替换jvm里已经加载的class方法。好处是可以恢复。
上传 .class 文件到服务器的技巧

性能监控

monitor:方法执行结果监控,统计重要信息。https://alibaba.github.io/arthas/monitor.html

$ monitor -c 5 demo.MathGame primeFactors
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 94 ms.timestamp            class          method        total  success  fail  avg-rt(ms)  fail-rate
-----------------------------------------------------------------------------------------------2018-12-03 19:06:38  demo.MathGame  primeFactors  5      1        4     1.15        80.00%timestamp            class          method        total  success  fail  avg-rt(ms)  fail-rate
-----------------------------------------------------------------------------------------------2018-12-03 19:06:43  demo.MathGame  primeFactors  5      3        2     42.29       40.00%timestamp            class          method        total  success  fail  avg-rt(ms)  fail-rate
-----------------------------------------------------------------------------------------------2018-12-03 19:06:48  demo.MathGame  primeFactors  5      3        2     67.92       40.00%timestamp            class          method        total  success  fail  avg-rt(ms)  fail-rate
-----------------------------------------------------------------------------------------------2018-12-03 19:06:53  demo.MathGame  primeFactors  5      2        3     0.25        60.00%timestamp            class          method        total  success  fail  avg-rt(ms)  fail-rate
-----------------------------------------------------------------------------------------------2018-12-03 19:06:58  demo.MathGame  primeFactors  1      1        0     0.45        0.00%timestamp            class          method        total  success  fail  avg-rt(ms)  fail-rate
-----------------------------------------------------------------------------------------------2018-12-03 19:07:03  demo.MathGame  primeFactors  2      2        0     3182.72     0.00%

tt:时空隧道,记录了过程中的快照,方便Arthas内部线程重新发起一次调用。https://arthas.aliyun.com/doc/tt.html

// 留下快照
$ tt -lINDEX   TIMESTAMP            COST(ms)  IS-RET  IS-EXP   OBJECT         CLASS                          METHOD
-------------------------------------------------------------------------------------------------------------------------------------1000    2018-12-04 11:15:38  1.096236  false   true     0x4b67cf4d     MathGame                       primeFactors1001    2018-12-04 11:15:39  0.191848  false   true     0x4b67cf4d     MathGame                       primeFactors1002    2018-12-04 11:15:40  0.069523  false   true     0x4b67cf4d     MathGame                       primeFactors1003    2018-12-04 11:15:41  0.186073  false   true     0x4b67cf4d     MathGame                       primeFactors1004    2018-12-04 11:15:42  17.76437  true    false    0x4b67cf4d     MathGame                       primeFactors91005    2018-12-04 11:15:43  0.4776    false   true     0x4b67cf4d     MathGame                       primeFactors
Affect(row-cnt:6) cost in 4 ms.
// 详细信息查询
$ tt -i 1003INDEX            1003GMT-CREATE       2018-12-04 11:15:41COST(ms)         0.186073OBJECT           0x4b67cf4dCLASS            demo.MathGameMETHOD           primeFactorsIS-RETURN        falseIS-EXCEPTION     truePARAMETERS[0]    @Integer[-564322413]THROW-EXCEPTION  java.lang.IllegalArgumentException: number is: -564322413, need >= 2at demo.MathGame.primeFactors(MathGame.java:46)at demo.MathGame.run(MathGame.java:24)at demo.MathGame.main(MathGame.java:16)Affect(row-cnt:1) cost in 11 ms.

发起执行

[arthas@10718]$ tt -t demo.MathGame run -n 5
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 56 ms, listenerId: 1INDEX      TIMESTAMP                   COST(ms)     IS-RET     IS-EXP      OBJECT              CLASS                                     METHOD
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------1000       2021-01-08 21:54:17         0.901091     true       false       0x7699a589          MathGame                                  run
[arthas@10718]$ tt -w '@demo.MathGame@random.nextInt(100)'  -x 1 -i 1000
@Integer[46]

trace:单纯时间统计https://arthas.aliyun.com/doc/trace.html

# 输出方法内部调用路径,并输出方法路径上的每个节点上耗时,根据耗时进行过滤
trace demo.MathGame run '#cost > 10' 

dump

dump:dump 已加载类的 bytecode 到特定目录. https://arthas.aliyun.com/doc/dump.html
heapdump:dump java heap, 类似jmap命令的heap dump功能。https://arthas.aliyun.com/doc/heapdump.html

heapdump --live /tmp/jvm.hprof# 之后使用tos回传
wget -O /usr/local/bin/toshelper http://tosv.byted.org/obj/ee-oi-intranet/toshelper && chmod +x /usr/local/bin/toshelper
toshelper /opt/tiger/multi-tenant-custom-entity/multi-tenant-custom-entity-cos-web/arthas-output/20210720-102201.svg

找到异常线程并查看堆栈

thread命令参看文章前半截
https://github.com/alibaba/arthas/issues/1202

方法一:
# 查找进程
top
# 查看进程线程
top -Hp 进程号
#或者也可以采用下面2种ps命令来查看繁忙的线程信息
ps -mp pid -o THREAD,tid,time
ps -Lfp pid 
# 16进制线程号
printf "%x\n" 目标线程号 
# jstack查看线程堆栈,jstack会打印出所有线程堆栈
jstack 进程号 | grep 线程ID方法二:
# show busy threads的方法:直接打印出异常线程堆栈
wget --no-check-certificate https://raw.github.com/oldratlee/useful-scripts/release-2.x/bin/show-busy-java-threads
chmod +x show-busy-java-threads./show-busy-java-threads方法三:
# Arthas方法,查找cpu占用量最高的线程
thread -n 10
# 查看堆栈
thread pid方法四:
# jstack 、top的文件也可以使用这个网站来分析
https://fastthread.io/ft-index.jsp

Mbean

命令介绍:https://arthas.aliyun.com/doc/mbean.html
什么是Mbean与jmx:
https://juejin.cn/post/6856949531003748365
https://www.liaoxuefeng.com/wiki/1252599548343744/1282385687609378
一种JVM运行时的监控框架。

案例总结

https://github.com/alibaba/arthas/issues?page=1&q=label%3Auser-case

trace查看耗时进行调优

https://github.com/alibaba/arthas/issues/1892
使用trace查看调用链路,从中分析耗时严重的函数。

Arthas底层实现

ByteKit解读:
https://github.com/alibaba/arthas/issues/1310
https://github.com/alibaba/arthas/issues/1311

WeakHashMap死循环引起CPU跑满

https://github.com/alibaba/arthas/issues/1709

thread + sc的应用
1,异常线程堆栈章节查到线程并且发现是weakHashMap的get方法出了问题
2,sc -d 从code-source中查看jar包,发现这个jar包里用到的是线程不安全版本的weakHashMap,遂破案。

JDK函数调用查询与后台脚本打印数据

案例:System.gc查找
https://github.com/alibaba/arthas/issues/20

stack:https://arthas.aliyun.com/doc/stack.html

实时观察版本:

# Arthas默认关闭了对JDK类的自带类的增强,需要通过options命令打开。
options unsafe true 
# stack命令:输出当前方法被调用的调用路径,实时观察谁调用了java.lang.System#gc,等待触发
# 实际上是不带每一步调用时间信息的trace版本
stack java.lang.System gc

后台打印版本

# 编辑脚本
cat system_gc.as# 脚本内容
options unsafe true
# 务必注意这里的-n,表示这个命令只执行一次,然后退出。如果不指定,Arthas 2.0会一直卡在那里,永远不退出,Arthas 3.0默认执行100次才会退出。在写批处理脚本的时候,请务必加上-n参数。
stack java.lang.System gc -n 1# 后台执行脚本1
./as.sh -b -f system_gc.as 59863 > system_gc.out 2>&1 &
# 后台执行脚本2,这种方式能够避免session因为连接超时中断的同时导致该脚本中断
nohup ./as.sh -b -f system_gc.as 59863 > system_gc.out 2>&1 &
# 后代执行脚本3,使用screen避免脚本中断
sudo yum install -b current screen
screen
./as.sh -b -f system_gc.as 59863 > system_gc.out 2>&1
# 即便网络断掉也没有问题。过一段时间之后,要查看之前的结果。如果连接断掉了,只需要输入以下命令
screen -r#过段时间观察即可
cat system_gc.out

ognl表达式筛选并观察输入输出

ognl表达式:https://github.com/alibaba/arthas/issues/11
一些例子:https://github.com/alibaba/arthas/issues/71

# 打印线上某个容器的size
ognl '@xxx.common.redis.collections.UniqConcurrentSet@INSTANCE.dataIsNullSet.size()
# 在内部类某个方法中查看外部类容器大小
# https://github.com/alibaba/arthas/issues/772
watch sun.net.httpserver.ServerImpl$ServerTimerTask1 run -f "target.this$0.allConnections.size()

查看某个Spring引用的具体实现

日志打满问题解决:https://github.com/alibaba/arthas/issues/237

# -d显示详细信息
sc -d *LarkService*
# 查看具体实现类
getstatic -c 73ad2d6 io.netty.channel.nio.NioEventLoop logger 'getClass().getName()'
getstatic -c 73ad2d6 io.netty.channel.nio.NioEventLoop logger 'logger'
getstatic -c 73ad2d6 io.netty.channel.nio.NioEventLoop logger 'logger.getClass().getProtectionDomain().getCodeSource().getLocation()'
field: logger
# 查询其基类的积累的logger实现
getstatic -c 73ad2d6 io.netty.channel.nio.NioEventLoop logger 'logger.parent.parent.parent.parent.parent'
field: logger

tt获取Spring容器内的bean

https://github.com/alibaba/arthas/issues/482
时空隧道中能抓取到bean的调用
实际上用的就是idea插件生成的ognl语句。

list出现环导致死循环引发的CPU负载过高

https://github.com/alibaba/arthas/issues/1202

thread
thread pid# 查看方法调用情况
tt -t com.google.common.collect.HashBiMap seekByKey -n 100# SpringMVC应用,所有请求都会被RequestMappingHandlerAdapter拦截,我们通过tt命令,监听invokeHandlerMethod的执行,然后在页面随便点点,就会得到以下内容
[arthas@384]$ tt -t org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter invokeHandlerMethod -n 10
Press Q or Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 622 ms.INDEX	COST(ms)  	OBJECT    	CLASS             METHOD                                             
------------------------------------------------------------------------------------1000 	481.203383	0x481eb705	RequestMappingHandlerAdapter    invokeHandlerMethod                                1001 	3.432024  	0x481eb705	RequestMappingHandlerAdapter	invokeHandlerMethod                               
...
# tt 命令会记录方法调用时的所有入参和返回值、抛出的异常、对象本身等数据。通过 -i 参数后边跟着对应的 INDEX 编号查看这条记录的详细信息。再通过-w参数,指定一个OGNL表达式,查找相关对象
# Arthas会把当前执行的对象放到target变量中,通过target.getApplicationContext()就得到了SpringContext对象,这里同上一节内容
# OGNL写一个函数,来实现链表的环路检测,在OGNL里写一段环路检测代码里是不太容易的,一个bucket不太可能有50个以上的节点,所以就通过遍历次数是否大于50来判断是否有环路。
tt -i 1000 -w 'target.getApplicationContext().getBean("oaInfoManager").userCache.entrySet().{delegate}.{^ #loopCnt = 0,#foundCycle = :[ #this == null ? false : #loopCnt > 50 ? true : (#loopCnt = #loopCnt + 1, #foundCycle(#this.nextInKToVBucket))], #foundCycle(#this)}.get(0)' -x 2

奇怪日志来源定位

https://github.com/alibaba/arthas/issues/263
实际上是通过重写StringBuilder代码来定位某个奇怪日志的stack
使用到的技术:
redefine

这篇关于Arthas(阿尔萨斯)定位线上问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/414240

相关文章

IDEA和GIT关于文件中LF和CRLF问题及解决

《IDEA和GIT关于文件中LF和CRLF问题及解决》文章总结:因IDEA默认使用CRLF换行符导致Shell脚本在Linux运行报错,需在编辑器和Git中统一为LF,通过调整Git的core.aut... 目录问题描述问题思考解决过程总结问题描述项目软件安装shell脚本上git仓库管理,但拉取后,上l

idea npm install很慢问题及解决(nodejs)

《ideanpminstall很慢问题及解决(nodejs)》npm安装速度慢可通过配置国内镜像源(如淘宝)、清理缓存及切换工具解决,建议设置全局镜像(npmconfigsetregistryht... 目录idea npm install很慢(nodejs)配置国内镜像源清理缓存总结idea npm in

pycharm跑python项目易出错的问题总结

《pycharm跑python项目易出错的问题总结》:本文主要介绍pycharm跑python项目易出错问题的相关资料,当你在PyCharm中运行Python程序时遇到报错,可以按照以下步骤进行排... 1. 一定不要在pycharm终端里面创建环境安装别人的项目子模块等,有可能出现的问题就是你不报错都安装

idea突然报错Malformed \uxxxx encoding问题及解决

《idea突然报错Malformeduxxxxencoding问题及解决》Maven项目在切换Git分支时报错,提示project元素为描述符根元素,解决方法:删除Maven仓库中的resolv... 目www.chinasem.cn录问题解决方式总结问题idea 上的 maven China编程项目突然报错,是

Python爬虫HTTPS使用requests,httpx,aiohttp实战中的证书异步等问题

《Python爬虫HTTPS使用requests,httpx,aiohttp实战中的证书异步等问题》在爬虫工程里,“HTTPS”是绕不开的话题,HTTPS为传输加密提供保护,同时也给爬虫带来证书校验、... 目录一、核心问题与优先级检查(先问三件事)二、基础示例:requests 与证书处理三、高并发选型:

前端导出Excel文件出现乱码或文件损坏问题的解决办法

《前端导出Excel文件出现乱码或文件损坏问题的解决办法》在现代网页应用程序中,前端有时需要与后端进行数据交互,包括下载文件,:本文主要介绍前端导出Excel文件出现乱码或文件损坏问题的解决办法,... 目录1. 检查后端返回的数据格式2. 前端正确处理二进制数据方案 1:直接下载(推荐)方案 2:手动构造

Python绘制TSP、VRP问题求解结果图全过程

《Python绘制TSP、VRP问题求解结果图全过程》本文介绍用Python绘制TSP和VRP问题的静态与动态结果图,静态图展示路径,动态图通过matplotlib.animation模块实现动画效果... 目录一、静态图二、动态图总结【代码】python绘制TSP、VRP问题求解结果图(包含静态图与动态图

MyBatis/MyBatis-Plus同事务循环调用存储过程获取主键重复问题分析及解决

《MyBatis/MyBatis-Plus同事务循环调用存储过程获取主键重复问题分析及解决》MyBatis默认开启一级缓存,同一事务中循环调用查询方法时会重复使用缓存数据,导致获取的序列主键值均为1,... 目录问题原因解决办法如果是存储过程总结问题myBATis有如下代码获取序列作为主键IdMappe

k8s容器放开锁内存限制问题

《k8s容器放开锁内存限制问题》nccl-test容器运行mpirun时因NCCL_BUFFSIZE过大导致OOM,需通过修改docker服务配置文件,将LimitMEMLOCK设为infinity并... 目录问题问题确认放开容器max locked memory限制总结参考:https://Access

Java中字符编码问题的解决方法详解

《Java中字符编码问题的解决方法详解》在日常Java开发中,字符编码问题是一个非常常见却又特别容易踩坑的地方,这篇文章就带你一步一步看清楚字符编码的来龙去脉,并结合可运行的代码,看看如何在Java项... 目录前言背景:为什么会出现编码问题常见场景分析控制台输出乱码文件读写乱码数据库存取乱码解决方案统一使