Arthas 怎么用?从安装到 watch 命令实战,线上排查不重启 JVM

发布时间:2026/7/22 2:42:15
Arthas 怎么用?从安装到 watch 命令实战,线上排查不重启 JVM 大家好我是程序员天天困。这是我的「Arthas 线上诊断实战」系列第 1 篇整个系列计划写 8 篇覆盖 watch、trace、vmtool、profiler、ognl 这些常用命令最后落到字节码增强原理。想看系列的可以点个关注断更不弃更。假如线上一个接口返回值莫名其妙偏大本地跑一遍完全复现不了。按老办法只能加日志、走测试、再灰度——一轮下来半天没了问题还可能因为重启就消失。最好的办法是用 Arthas一条watch命令贴上去三分钟就能定位到问题如果你也经常被「线上没日志、本地复现不了、又不能随便重启」这三件事卡住这篇就把 Arthas 的入门姿势一次讲清楚它是什么、怎么装、watch命令怎么抓出入参。点个收藏我们开始一、Arthas 是什么官方对它的定义是Arthas 是一款线上监控诊断产品通过全局视角实时查看应用 load、内存、gc、线程的状态信息并能在不修改应用代码的情况下对业务问题进行诊断包括查看方法调用的出入参、异常监测方法执行耗时类加载信息等大大提升线上问题排查效率。——Arthas 官方文档·简介Arthas阿尔萨斯Alibaba 开源的 Java 线上诊断工具能在不重启 JVM、不改业务代码的前提下观察方法的出入参、异常、耗时和运行时状态。你可以把它理解为「给运行中的 JVM 外接一个仪表盘不动它的内部运转就能看到哪不对」。它是 Alibaba 开源的 Java 诊断工具深受开发者喜爱。当你遇到下面这些束手无策的问题时它能帮你解决这个类从哪个 jar 包加载的为什么会报各种类相关的 Exception我改的代码为什么没有执行到难道是我没 commit分支搞错了遇到问题无法在线上 debug难道只能通过加日志再重新发布吗线上遇到某个用户的数据处理有问题但线上同样无法 debug线下无法重现是否有一个全局视角来查看系统的运行状况有什么办法可以监控到 JVM 的实时运行状态怎么快速定位应用的热点生成火焰图怎样直接从 JVM 内查找某个类的实例Arthas 4.x 支持 JDK 8包括 JDK 17、JDK 21 和 JDK 25支持 Linux/Mac/Windows采用命令行交互模式同时提供丰富的 Tab 自动补全功能进一步方便进行问题的定位和诊断。我自己的体感是Arthas 对于 Java 后端就像电工师傅手里的电笔——线上有没有问题、问题落在哪个方法一搭就知道不必为了排查把服务停了或重启。这个系列我会一篇一篇把常用命令过一遍第一篇就从最常用的watch开始。二、为什么需要 Arthas本地开发环境访问不到生产环境生产出了问题没法用 IDE 远程调试——何况调试会暂停所有线程等于让服务停摆。想在测试或预发环境复现有些问题跟环境强相关复现不了甚至一重启就消失。加日志排查又得走「测试→预发→生产」一整套等发上去 JVM 一重启现场可能就没了。Arthas 解决的就是这个困局在线解决生产问题既不重启 JVM也不改业务代码以观察者身份介入不暂停任何线程。三、动手前的准备装 IDEA 插件在用之前先装一个 IDEA 插件帮我们快速生成 Arthas 命令省得手敲一长串类名方法名。打开 IDEA 的 Settings → Plugins → Marketplace搜Arthas即可找到。装完之后在任意一个方法上右键菜单里会多出一组 Arthas 命令watch、trace、stack 等点一下就把对应命令复制到剪贴板。四、启动 Arthas 并 Attach 到目标进程插件装好接下来启动 Arthas 本体。它就是一个可执行 jar两行命令搞定curl-Ohttps://arthas.aliyun.com/arthas-boot.jarjava-jararthas-boot.jar启动之后Arthas 会先检查当前机器上有哪些 Java 进程列成一个带序号的清单Attach附加连接Arthas 通过 JVM 自带的 Attach API 把自己「挂」到目标 Java 进程上注入一段诊断代码从而观察方法调用。它走的是观察者模式不会暂停线程所以能在生产环境安全使用。你可以理解为「给运行中的 JVM 外接一个仪表盘不动它的内部运转」。直接输入目标进程对应的序号回车Arthas 就会 Attach 上去Attach 成功后命令行提示符会变成[arthasPID]$意味着你已经在目标进程里了可以开始下诊断命令。五、watch 命令实战揪出那个多 1 的 bug接下来用一个实际例子看 watch 到底怎么用。先看一段最简单的程序RequestMapping(path/user/calculate,methodRequestMethod.GET)publicIntegercalculate(RequestParamIntegerx,RequestParamIntegery,RequestParam(nameop)Stringop){returndoCalculate(x,y,op)1;// 玄机就在这一行}publicintdoCalculate(intx,inty,Stringop){if(add.equals(op))returnxy;elseif(sub.equals(op))returnx-y;elseif(mul.equals(op))returnx*y;elseif(div.equals(op))returnx/y;elsethrownewUnsupportedOperationException(NotSupportOpop);}这个接口算 x 和 y 的运算结果。注意calculate第 5 行有个 bug把doCalculate的结果又1了。从调用方看结果就是错的但逻辑一长肉眼一行行看代码很难一眼定位。用 Arthas我们可以动态观察doCalculate的返回值一步一步排查根本不用改代码。watch方法观察命令Arthas 的核心命令之一在目标方法每次被调用时拦截按你给的表达式打印入参、返回值或异常。你可以理解为「在方法门口装了个摄像头谁进谁出、带了什么、摔没摔跤全拍下来」。在 IDEA 里对doCalculate方法右键 → Arthas → watch会复制出这样一条命令复制出来的命令长这样watchcom.ttk.controller.WebController doCalculate{params,returnObj,throwExp}-n5-x3这条命令我详细拆开讲每一段都别记错watch—— 表示当前要用的命令是 watch。org.example.controller.WebController—— 目标类的全限定名。doCalculate—— 目标方法名。{params,returnObj,throwExp}—— 要观察的对象用 OGNL 表达式包起来params对应方法的入参集合returnObj对应方法走完后的返回结果throwExp对应方法抛出的异常对象。合起来就是对这个方法的出入参和异常一起做诊断。-n 5—— 诊断的次数比如只观察 5 次调用就自动退出。-x 3—— 输出对象时展开的层级这个不太好理解后面单独用例子讲。把这条命令复制到 Arthas 终端然后触发一次调用curlhttp://localhost:8080/user/calculate?x1y2opadd可以看到入参 x1、y2、opadd返回值是 3说明doCalculate本身的计算没问题最后一个是 null表示异常为 null也就是没发生异常。这时候我们再去 watch 外层的calculate方法watchcom.ttk.controller.WebController calculate{params,returnObj,throwExp}-n5-x3就会发现返回值赫然是 4。两边一对比问题就在calculate多写的那个1上——这样很快就能找到问题所在没动一行业务代码。六、异常观察throwExp 不再是 null上面我们看到如果方法抛了异常watch 也是能观察到的。比如把请求的 op 换成add2doCalculate就会抛出UnsupportedOperationException这时候再 watch你会发现第三个对象throwExp不再是 null 了而是对应的异常对象加完整的堆栈信息。这就是throwExp的意义——正常时是 null抛异常时给你完整的异常现场不用再去翻日志。七、-x 的用法看穿嵌套 Map回到最开始那条命令里的-xwatchcom.ttk.controller.WebController calculate{params,returnObj,throwExp}-n5-x3-x表示展开的层级直接讲不好理解看个例子就懂了。假如有个参数嵌套很深的方法publicIntegerdoCalculate2(MapString,MapInteger,SetIntegerdata){for(Map.EntryString,MapInteger,SetIntegerentry:data.entrySet()){Stringopentry.getKey();MapInteger,SetIntegervalueentry.getValue();Map.EntryInteger,SetIntegerdata_opvalue.entrySet().stream().findAny().get();intxdata_op.getKey();intydata_op.getValue().stream().findAny().get();returndoCalculate(x,y,op);}return0;}遇到这种参数嵌套好几层的直接 watch 一下watch com.ttk.controller.WebController doCalculate2 {params,returnObj,throwExp} -n 5 -x 3发送请求curl http://localhost:8080/user/calculate2你会发现只能看到 Map 第一个 key 是啥里面套的 Map 和 Set 全看不出来。这时候把-x调成 4就能看到前两层了以此类推-x调得越大展开越深。一句话-x就是「你愿意看到第几层」。八、params 的操作只看你想看的那一个继续回到这条命令watchcom.ttk.controller.WebController calculate{params,returnObj,throwExp}-n5-x3注意这里的params是 param 的复数——因为函数参数有很多个。如果我们只想看其中一个呢比如这个方法publicintdoCalculate(intx,inty,Stringop){if(add.equals(op))returnxy;elseif(sub.equals(op))returnx-y;elseif(mul.equals(op))returnx*y;elseif(div.equals(op))returnx/y;elsethrownewUnsupportedOperationException(NotSupportOpop);}我只想看op很简单watchcom.ttk.controller.WebController calculate{params[2]}-n5-x3params本质是个数组索引从 0 数起0 就是第一个参数1 是第二个2 就是第三个依此类推。甚至你还可以在params上做一些简单的计算操作比如观察这两个入参的和watchcom.ttk.controller.WebController calculate{params[0]params[1]}-n5-x3这就是 watch 的用法。稍微引申一下watch 拿到的观察对象固定就三个params方法被调用时传进来的参数按数组形式组织returnObj方法正常走完时返回的结果throwExp方法如果抛了异常这里就是那个异常。围绕这三个对象你还能塞进简单的表达式做运算比如下钻取属性、对入参做加减、把两个对象拼一起看日常排查里八九成的场景都能覆盖。结语Arthas 解决的就是「线上有现场、但不能动现场」这个死结而watch是它最趁手的那把螺丝刀——一行命令出入参异常全在眼前。这一篇我们摸了watch的皮毛下一篇聊trace看怎么定位「一个请求里到底哪一行最耗时」。本文基于 Arthas 4.x 官方文档与个人实践整理命令参数以官方文档为准。我是程序员天天困持续分享编程干货。觉得有用的话记得点赞收藏和关注~也欢迎在评论区聊聊你在线上排查 bug 时被哪个「没打日志的角落」坑过最久。