⭐ 推荐:社区规则条款 V1.0

如何用 Arthas 在线诊断 Java 生产环境问题?

GJ
GJ 资深会员 👑黑卡会员
发布于 2026-10-25 00:53 ·6 浏览 ·0 回复
内容摘要

Arthas 可通过 Java Agent 挂载到运行中的 JVM,在不重启、不改代码的前提下,按 attach、dashboard/thread、sc/sm/jad、watch 的流程定位 CPU 飙高、接口变慢、返回值异常和死锁,并需注

学完这篇,你能在不重启、不改代码的前提下,用 Arthas 定位 Java 线上服务的 CPU 飙高、接口变慢、返回值不对、死锁这几类常见故障。

现在很多团队都会在服务器上常备一个 Arthas 包,它通过 Java Agent 挂到正在运行的 JVM 上。前提有两个:目标进程是用 JDK 启动的(不是精简过的 JRE),并且执行 java -jar 的用户与该进程的用户一致,否则会 attach 失败。

第一步:把 Arthas 挂到目标进程上

这一步的目标是让 Arthas 连上你的业务 JVM,连上后会看到一个 [arthas@进程号]$ 的命令提示符。

curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar

执行之后它会列出当前机器上所有 Java 进程,输入序号回车即可。如果服务器不能连外网,先在有网机器上下载全量包再上传;如果 attach 卡住,加上 --telnet-port 9999 --http-port 9998 换端口重试。

注意:Arthas 4.x 需要 JDK 8 及以上,但attach 到 JDK 6/7 的老应用要用 Arthas 3.x 版本,版本对不上会直接报错退出。

第二步:先用 dashboard 和 thread 了解整体情况

这一步是为了在动任何命令之前,看清 CPU、内存、线程的整体状况,避免一上来就抓细节。

输入 dashboard 会出现一个 5 秒刷新的实时面板,看到线程列表、堆内存、GC 次数和几个最忙的线程。按 q 退出。

接着专看线程:

thread -n 3        # CPU 占用最高的 3 个线程及堆栈
thread -b          # 检测死锁,有死锁会直接打印
thread --state BLOCKED   # 列出所有阻塞线程

thread -n 3 输出的堆栈是排查 CPU 飙高的第一手证据,通常能直接看出是死循环、正则回溯还是某个序列化在耗 CPU。

注意:thread -b 只能发现synchronized造成的死锁,ReentrantLock 之类的锁它查不出来,这种情况要用 jstack 配合看。

第三步:确认线上跑的是不是你以为的那版代码

这一步解决"我本地明明是好的"这类问题,确认类从哪个 jar 加载、方法签名是什么、实际字节码长什么样。

sc -d com.example.order.OrderService        # 类信息:ClassLoader、来自哪个 jar
sm com.example.order.OrderService getOrder  # 方法签名与参数类型
jad com.example.order.OrderService          # 反编译出源码

sc -d 里的 classLoaderHash 后面会用到,jad 出来的代码就是线上真正在跑的代码,跟你 IDE 里那份对比一下,版本不一致、被热更新覆盖过的问题立刻现形。

第四步:用 watch 抓入参、返回值和异常

这一步用来回答"这个方法到底收到了什么、返回了什么、有没有抛异常",是排查业务逻辑问题最常用的手段。

watch com.example.order.OrderService getOrder \
  '{params, returnObj, throwExp}' -x 3 -n 5

参数含义:-x 3 是展开层级(对象字段打深一层就够,别开太大),-n 5 是最多观测 5 次后自动结束,-e 是只在抛异常时打印。想看方法执行前的入参就加 -b,执行后加 -s。

注意:watch 不带 -n 会一直挂着打印,如果方法本身是高频调用,日志量会瞬间压垮磁盘。生产上务必给 -n,并在排查完后 stop 退出。

第五步:用 trace 和 monitor 定位慢在哪

这一步解决"接口慢但不知道慢在哪一行"的问题。

trace com.example.order.OrderService getOrder -n 5 --skipJDKMethod true
monitor -c 5 com.example.order.OrderService getOrder

trace 会打印方法内部每个子调用的耗时,--skipJDKMethod true 可以过滤掉 JDK 内部方法,输出干净很多。monitor -c 5 每 5 秒输出一次该方法的调用次数、成功率和平均 RT,适合判断是偶发还是持续性劣化。

如果只想看是谁调用了这个方法,用 stack com.example.order.OrderService getOrder -n 3。

注意:trace 对每个子调用都做字节码增强,深度大的方法会有明显性能损耗。生产上先加 -n,别在交易高峰期长时间挂着。

第六步:查配置、查 Bean、改日志级别

这一步不用重启就能确认配置值、捞到 Spring 容器里的 Bean、临时调日志级别。

vmtool --action getInstances --className org.springframework.context.ApplicationContext \
  --express 'instances[0].getBean("orderService")'
ognl '@java.lang.System@getProperty("spring.profiles.active")'
logger --name com.example --level debug

logger 改完立即生效,排查完记得用 logger --name com.example --level info 改回去。

第七步:收尾

排查结束后执行 stop 退出当前会话,shutdown 关闭 Arthas 服务端;如果只是临时观察,stop 就够了,不会影响业务进程。

注意:redefine 热更新只能改方法体,改不了方法签名和字段,且编译用的 JDK 版本必须与目标进程一致,生产环境建议只在预发演练过再用。

小结

  • 启动:java -jar arthas-boot.jar 选进程号,用户权限要和目标 JVM 一致。
  • 看全局:dashboard 看面板,thread -n 3 看 CPU 热点,thread -b 查死锁。
  • 验代码:sc -d 看类来源,jad 反编译对比版本。
  • 抓数据:watch 看参数/返回值/异常,务必带 -n 控次数。
  • 找耗时:trace 定位慢子调用,monitor 看整体 RT 与成功率。
  • 查配置:vmtool 拿 Bean,ognl 读系统属性,logger 临时调级别。
  • 用完 stop 退出,热更新和 trace 都要先在预发验证。
本文转载自 GJ站长论坛,原文地址:https://www.gj0.com/thread-2516.html
转载请注明出处,版权归原作者所有。
—/ 5暂无评分
还没有评分,来打第一分吧

全部回复 0

还没有回复,来抢沙发~