暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

线上问题追踪诊断工具Arthas

Sumslack团队 2021-04-28
1705

背景

有时,我们要追踪一个线上问题是困难的,比如,它不一定在测试环境能复现,打的补丁在测试环境测试通过,到了生产还是无法修复,无法快速给线上程序打补丁,线上问题怎么Debug?Arthas
应用而生,它可以帮助你解决:

这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!是否有一个全局视角来查看系统的运行状况?有什么办法可以监控到JVM的实时运行状态?怎么快速定位应用的热点,生成火焰图?

环境搭建

IDEA插件安装

Plugins
搜索arthas
,安装两个插件:arthas idea
,ArthasHotSwap
,前者为了更快的生成命令行,就是通过IDEA操作将相应命令拷贝到你剪贴板,比如对方法的watch等,后者为了实现简单便捷的热部署。

服务器安装

以上拷贝的命令必须在服务器的终端中运行,所以必须在服务端运行一个Java程序,可以利用最简便的安装方式:

curl -L https://arthas.aliyun.com/install.sh | sh
复制

Linux需安装unzip

只要运行as.sh
就会进入arthas
命令终端模式,然后利用IDEA插件操作的命令行黏贴到这里就能运行,在运行as.sh
的时候,arthas
会让你选择选用哪个Java进程,如下图:选择一个进程后,我们可以看看终端支持的命令:

以上环境准备完毕,说白了,就是在服务器上通过arthas
终端,让你有途径全方位监控你的程序,以便让你发现问题(提供了Debug环境,会输出入参,返回值,捕获异常)。

使用

观测函数(watch)

针对线上特定的某次请求异常(可能存在边界等问题,没被QA测试覆盖到),那么我们可以通过监控某个函数观察他入参为什么没有达到我们预期结果,可以在IDEA中在该方法右键,选择:``剪贴板会出现命令黏贴到arthas
命令终端:

watch com.sumscope.data.controller.StatController totalByDay '{params,returnObj,throwExp}' -v -n 5 -x 3 'params[0]=="xxx"'
复制

命令解释:'{params,returnObj,throwExp}' 表示观测对象,这里选择了入参、出参和异常,-n 5 表示观测到5次后停止,-x 3 表示打印观测对象的时候只打印3层嵌套结构,注意最后部分,可以针对入参写出你的筛查条件,以便在生产环境中筛选出达不到预期结果的某个请求。

函数调用复盘(tt)

Arthas的tt命令可以获取方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测。watch 虽然很方便和灵活,但需要提前想清楚观察表达式的拼写,这对排查问题而言要求太高,因为很多时候我们并不清楚问题出自于何方,只能靠蛛丝马迹进行猜测。这个时候如果能记录下当时方法调用的所有入参和返回值、抛出的异常会对整个问题的思考与判断非常有帮助。于是乎,TimeTunnel 命令就诞生了。比如以下记录了该文件每次执行的时间点: tt -t com.sumscope.data.controller.StatController$_$EnhancerBySpringCGLIB$_$c7756535 totalByDay
可以通过以下命令复盘某次请求:tt -p -i 1000
 其中1000是上面截图中的INDEX列的值。不仅如此,还可以以某个频率复盘某次请求:tt -p --replay-times 5 --replay-interval 2000 -i 1000
表示重新触发5次,每次间隔2s。复盘请求时,还想watch该次请求,可以通过重新开一个终端。

线上热部署(ArthasHotSwap)

通过观测函数,如果我们想修复方法体代码,然后发布到线上看看效果,那么就需要用到ArthasHotSwap
arthas
命令终端执行:

sudo echo "curl -L http://xxxtai-arthas-hot-swap.oss-cn-beijing.aliyuncs.com/public/Cvcc3XtNcrOC5i9Lqgqwnd6siee8Y9xPVG3iMFWQBbM=x  > HotSwapScript4OneClass.sh ;
echo 'ab09861537c0d108294f6f458feb8fcf HotSwapScript4OneClass.sh' > HotSwapScript4OneClass.md5sum;
md5sum --status -c ./HotSwapScript4OneClass.md5sum;
if [[ \$? -eq 0 ]]; then
chmod +x HotSwapScript4OneClass.sh;
yes | ./HotSwapScript4OneClass.sh 5b0f5d1176386d55271c5b3609753658 53643e290d2d0b7c145b700131021745;
else
echo 'It is necessary to report this error to xxxtai@163.com!!!';
fi" > ArthasHotSwapMD5Check.sh; chmod +x ./ArthasHotSwapMD5Check.sh; ./ArthasHotSwapMD5Check.sh;
复制

执行后,再请求一下函数,然后看看是否修复,如果修复了,就可以提交你的代码了(一般不建议这么做,除非确实有必要,比如线上比较怪异的bug)

Arthas 基础命令

help——查看命令帮助信息cls——清空当前屏幕区域session——查看当前会话的信息reset——重置增强类,将被 Arthas 增强过的类全部还原,Arthas 服务端关闭时会重置所有增强过的类version——输出当前目标 Java 进程所加载的 Arthas 版本号history——打印命令历史quit——退出当前 Arthas 客户端,其他 Arthas 客户端不受影响stop——关闭 Arthas 服务端,所有 Arthas 客户端全部退出keymap——Arthas快捷键列表及自定义快捷键

其他有用命令

jad:反编译某个函数,一般用在线上代码有问题时,看看是否是代码发布时,选错了版本; jad 类全名通配符 函数名(可选) --lineNumber(显示行号)
sc:查看已加载的类信息,这个命令当被第三方修改了字节码的时候,特别有用 sc 类全名通配符 函数名通配符 -d(详情) -f(输出类成员变量信息) -E(开启正则匹配)
dashboard:当前系统的实时数据面板,按 ctrl+c 退出monitor:方法执行监控,比如每隔5秒统计某个方法执行次数,也可以执行入参过滤条件 monitor -c 5 -E(开启正则匹配)类全名通配符 函数名通配符 "params[0] <= 2"
thread:查看当前线程信息,查看线程的堆栈,如thread -n 3
jvm:查看当前JVM信息sysprop:查看当前JVM的系统属性(System Property)sysenv:查看当前JVM的环境属性(System Environment Variables)vmoption:查看,更新VM诊断相关的参数,如vmoption PrintGCDetails
perfcounter:查看当前JVM的 Perf Counter信息logger:查看logger信息,更新logger levelmbean:查看 Mbean 的信息,这个命令可以便捷的查看或监控 Mbean 的属性信息。getstatic:推荐直接使用ognl命令,更加灵活。通过getstatic命令可以方便的查看类的静态属性。ognl:执行ognl表达式,如调用静态函数:ognl '@java.lang.System@out.println("hello")'
,获取静态字段:ognl '@demo.MathGame@random'
sm:查看已加载类的方法信息,这个命令能搜索出所有已经加载了 Class 信息的方法信息。dump:dump 已加载类的 bytecode 到特定目录,如dump -d /tmp/output java.lang.String
heapdump:dump java heap, 类似jmap命令的heap dump功能。classloader:查看classloader的继承树,urls,类加载信息,classloader 命令将 JVM 中所有的classloader的信息统计出来,并可以展示继承树,urls等。mc:Memory Compiler/内存编译器,编译.java文件生成.class。retransform:加载外部的.class文件,retransform jvm已加载的类。retransform /tmp/Test.class
,通过-d参数删除外部类,通过--deleteAll删除所有外部类
redefine:推荐使用 retransform 命令,redefine命令和jad/watch/trace/monitor/tt等命令会冲突。执行完redefine之后,如果再执行上面提到的命令,则会把redefine的字节码重置。原因是jdk本身redefine和Retransform是不同的机制,同时使用两种机制来更新字节码,只有最后修改的会生效。trace:方法内部调用路径,并输出方法路径上的每个节点上耗时,trace 命令能主动搜索 class-pattern/method-pattern 对应的方法调用路径,渲染和统计整个调用链路上的所有性能开销和追踪调用链路。stack:输出当前方法被调用的调用路径,很多时候我们都知道一个方法被执行,但这个方法被执行的路径非常多,或者你根本就不知道这个方法是从那里被执行了,此时你需要的是 stack 命令。profiler:使用async-profiler生成火焰图,profiler 命令支持生成应用热点的火焰图。本质上是通过不断的采样,然后把收集到的采样结果生成火焰图。cat:打印文件内容,和linux里的cat命令类似。base64:base64编码转换,和linux里的 base64 命令类似。tee:类似传统的tee命令, 用于读取标准输入的数据,并将其内容输出成文件。tee指令会从标准输入设备读取数据,将其内容输出到标准输出设备,同时保存成文件。如:sysprop | tee -a /path/to/logfile | grep java
auth:验证当前会话,在attach时,可以在命令行指定密码。

常见错误

Enhance error! exception: java.lang.ClassFormatError

我们项目引入了skyworking
,AOP技术修改了Java字节码的,先使用sc
命令获取真实的类名再自行即可,比如如下(注意黑体部分):watch com.sumscope.data.controller.StatController$$EnhancerBySpringCGLIB$$c7756535 totalByDay '{params,returnObj,throwExp}' -v -n 5 -x 3 '1==1'

target process not responding or HotSpot VM not loaded

检查当前用户和目标java进程是否一致。如果不一致,则切换到同一用户。JVM只能attach同样用户下的java 进程。尝试使用 jstack -l $pid,如果进程没有反应,则说明进程可能假死,无法响应JVM attach信号。所以同样基于attach机制的Arthas无法工作。尝试使用jmap heapdump后分析。尝试按quick-start里的方式attach math-game。更多情况参考:https://github.com/alibaba/arthas/issues/347

你可以继续阅读:


一款自动生成后台代码的管理系统的设计与实现 “大”中台,“小”前端的架构演变| 云服务平台中推送服务的设计与实现 | 对微服务的理解以及实现一套微服务对外发布API管理平台 | 项目开发中常用的设计模式整理 | 异构语言调用平台的设计与实现 | 大话正则表达式 | 云API平台的设计与实现 | 个税改了,工资少了,不要慌!文末附计算器


关注我们的公众号 

长按识别二维码关注我们


文章转载自Sumslack团队,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论