Arthas 概述:无需重启的线上诊断利器

📅 2026/7/23 10:33:54 👁️ 阅读次数 📝 编程学习
Arthas 概述:无需重启的线上诊断利器

Arthas 概述:无需重启的线上诊断利器


线上系统出现问题时,传统的排查手段存在明显局限。加日志需要修改代码、提交、构建、部署,整个流程耗时至少数十分钟,而且重启会导致问题现场被破坏,难以复现。Arthas 是阿里巴巴开源的 Java 诊断工具,通过字节码增强技术,可以在不重启 JVM、不修改代码的前提下,实时查看方法调用信息、监控 JVM 状态、追踪调用链路。


Arthas 的核心能力包括:在线查看方法入参和返回值、反编译源码、监控方法执行耗时、追踪调用路径、热替换代码。其中 watch 命令是最常用的功能之一,它可以直接观察指定方法的每一次调用,包括入参、返回值和异常信息。


---


2. Arthas 的安装与快速启动


2.1 下载与启动


Arthas 是一个独立的 jar 包,下载后直接通过 java 命令启动:


# 下载 arthas-boot.jar curl -O https://arthas.aliyun.com/arthas-boot.jar # 启动 Arthas,自动列出当前机器上运行的所有 Java 进程 java -jar arthas-boot.jar


启动后,Arthas 会列出当前系统中的 Java 进程,输入序号选择要诊断的目标进程。连接成功后进入 Arthas 的命令行交互界面。


2.2 基于 Docker 环境的快速接入


对于容器化部署的服务,可以通过kubectl exec进入容器后下载并启动 Arthas:


kubectl exec -it order-service-7d4f8b9c6-xz2kq -- /bin/bash # 在容器内下载并启动 curl -O https://arthas.aliyun.com/arthas-boot.jar java -jar arthas-boot.jar


选择 PID 为 1 的 Java 进程即可。对于基于 JRE 基础镜像的容器,可能缺少 curl 命令,可以在本地下载后通过kubectl cp拷贝到容器中。


---


3. watch 命令深度解析:观察方法调用的神眼


3.1 watch 命令的基本语法


watch <类名> <方法名> <观察表达式> <条件表达式>


  • 类名:全限定类名,支持通配符。
  • 方法名:方法名称,支持通配符。
  • 观察表达式:指定要查看的内容,常用值为{params, returnObj, throwExp}
  • 条件表达式:过滤条件,只有满足条件的调用才会输出。不指定则输出所有调用。


3.2 查看方法入参和返回值


这是最基础的使用场景:在不加日志的情况下,观察某个方法的实际调用情况。


# 观察 OrderService.createOrder 方法的入参和返回值 watch com.example.service.OrderService createOrder '{params, returnObj}' -x 3


params表示方法的所有入参。returnObj表示方法的返回值。-x 3指定输出结果中对象的展开深度为 3 层。如果不指定展开深度,嵌套对象默认只显示第一层的引用地址。


ClientOrderService目标 JVMArthas Agent运维人员ClientOrderService目标 JVMArthas Agent运维人员增强完成,等待方法调用watch OrderService createOrder '{params, returnObj}' -x 3字节码增强在 createOrder 方法前后插入探针调用 createOrder(order, userId)触发探针,记录 params执行业务逻辑触发探针,记录 returnObj返回结果输出:params=[Order{id=null, amount=100}, 12345]returnObj=OrderResult{code=0, msg='成功'}


3.3 watch 命令的输出格式说明


Arthas 会将每次方法调用的观察结果格式化输出,典型输出如下:


ts=2024-01-15 14:30:25; [cost=45ms] result=@ArrayList[ @Object[][ @Order[id=null,amount=100.0,userId=12345], @String[normal], ], @OrderResult[code=0,msg="创建成功",orderId=98765], ]


  • ts:方法调用发生的时间戳。
  • cost:方法执行的耗时,单位毫秒。
  • result:观察表达式求值的结果。外层数组的第一个元素是params,第二个元素是returnObj


3.4 条件过滤:精准捕获异常调用


在生产环境中,目标方法的调用频率可能非常高。输出所有调用会产生大量无效信息,既刷屏又消耗 Arthas 的采样资源。条件表达式用于过滤出有诊断价值的具体调用。


# 仅观察入参中金额大于 10000 的调用 watch com.example.service.OrderService createOrder '{params, returnObj}' 'params[0].amount > 10000' -x 3 # 仅观察特定用户的调用 watch com.example.service.OrderService createOrder '{params, returnObj}' 'params[1].equals("12345")' -x 3


条件表达式使用 OGNL 语法,可以访问入参、返回值、异常对象的属性。当方法有多个重载时,条件表达式的参数索引与运行时实际传入的参数顺序一致。


3.5 异常捕获:在线定位报错的根本原因


当线上偶尔抛出异常,但日志不够详细时,watch 命令可以直接捕获异常的完整堆栈信息。


# 观察方法抛出异常时的入参和异常信息 watch com.example.service.OrderService createOrder '{params, throwExp}' -e -x 3


-e参数表示仅在方法抛出异常时触发观察。throwExp代表异常对象。结合条件表达式,可以进一步缩小范围:


# 仅在抛出特定异常类型时触发 watch com.example.service.OrderService createOrder '{params, throwExp}' \ 'throwExp instanceof java.lang.NullPointerException' -e -x 3


这个能力在生产故障排查中极具价值。当某个接口开始返回 500 错误,但又无法从现有日志定位原因时,通过-e参数可以直接抓取到异常发生时的完整调用上下文,包括方法入参和异常堆栈。


3.6 调用频率限制:保护目标 JVM 的性能


在高 QPS 的服务上使用 watch 命令,如果不加限制,会显著增加目标方法的执行开销。-n参数可以限制输出的次数:


# 仅输出前 5 次调用,之后自动终止观察 watch com.example.service.OrderService createOrder '{params, returnObj}' -x 3 -n 5


-n次数达到后,Arthas 会自动移除对该方法的字节码增强,恢复原始性能。建议在初次使用 watch 时先设置较小的-n值,确认过滤条件正确后再调整。


---


4. watch 命令的观察表达式详解


观察表达式是 watch 命令最灵活的部分。它本质上是一个 OGNL 表达式,Arthas 会将每次方法调用的上下文注入到表达式的求值环境中。


4.1 内置变量列表


| 变量名 | 说明 |

| :--- | :--- |

|params| 方法的入参数组,params[0]表示第一个参数。 |

|returnObj| 方法的返回值。正常返回时有值,抛出异常时为 null。 |

|throwExp| 方法抛出的异常对象。正常返回时为 null。 |

|target| 方法调用的目标对象,即 this。 |

|clazz| 目标对象的 Class 对象。 |


4.2 构造自定义输出


观察表达式可以构造自定义的数据结构来聚焦关注的信息:


# 仅输出入参的第一个参数和返回值的 code 字段 watch com.example.service.OrderService createOrder \ '{params[0], returnObj.code}' -x 2


也可以在表达式中进行简单的计算和条件判断:


# 当返回值 code 不为 0 时,输出入参和返回值 watch com.example.service.OrderService createOrder \ '{params, returnObj}' 'returnObj.code != 0' -x 2


4.3 追踪方法内部耗时


在观察表达式中可以使用#cost变量获取方法执行的总耗时:


# 输出方法入参和执行耗时 watch com.example.service.OrderService createOrder \ '{params, #cost}' 'params[0].amount > 10000' -x 2


#cost是 Arthas 注入的特殊变量,表示当前调用从进入到返回的总耗时,单位毫秒。这对于定位慢请求非常有效。


---


5. 基于 Arthas 的线上问题排查完整流程


接口报错接口耗时变长逻辑结果不符合预期

收到线上告警

问题类型判断

watch -e 抓取异常
查看入参和异常堆栈

定位异常原因
是否入参异常导致?

检查上游调用方
修复入参问题

根据异常堆栈
定位代码 Bug

watch 观察耗时
参数和耗时(含cost)

耗时是否集中在
特定入参?

分析特定入参
是否触发慢 SQL 或慢调用

使用 trace 命令
追踪内部调用链路耗时

watch 观察入参和返回值
参数和返回对象

对比预期与实际
定位逻辑分支

使用 jad 反编译源码
确认代码版本是否正确

修复代码上线


Arthas 的核心价值在于它提供了一个在线观察窗口。传统排查是“猜问题 - 加日志 - 重启 - 验证”的反复循环,而 Arthas 将这个过程变为“观察现象 - 定位根因 - 一次修复”。每一次省去的重启,都是对生产环境稳定性的保护。


---


6. Arthas 的其他常用命令速览


watch 命令解决的是方法级别的入参和返回值观察,但完整的线上诊断往往需要多个命令配合。


6.1 trace 命令:追踪方法内部调用路径与耗时


trace com.example.service.OrderService createOrder


trace 会输出createOrder方法内部所有子调用的耗时树形图,清晰展示每一层调用的时间占比。当 watch 确认了某个方法总体耗时异常后,trace 用来向下钻取具体的耗时点。


6.2 jad 命令:在线反编译源码


jad com.example.service.OrderService createOrder


jad 直接反编译运行中的 class 文件,输出 Java 源码。这对于验证部署的代码版本是否正确、确认线上实际运行的逻辑非常有帮助。如果怀疑回滚未生效或代码未同步,jad 是最直接的验证工具。


6.3 tt 命令:方法执行数据时空隧道


tt -t com.example.service.OrderService createOrder


tt 是 Time Tunnel 的缩写。它会记录方法每次调用的入参、返回值、异常、耗时等完整信息,并保存在一个时间碎片中。之后可以通过索引号随时回放某次调用的现场。tt 适合排查那些难以复现的偶发问题:先在线上开启记录,问题复现后再回放现场。


6.4 dashboard 命令:实时 JVM 监控面板


dashboard


dashboard 输出一个实时刷新的 JVM 监控面板,包括线程使用情况、内存各区域占用、GC 次数和耗时、CPU 使用率等。这是接入 Arthas 后的第一个诊断动作,用于快速判断 JVM 的整体健康状态。


6.5 vmtool 命令:强制 GC 和内存分析


vmtool --action forceGc vmtool --action getInstances --className java.lang.String --limit 10


vmtool 提供了对 JVM 内部的直接操作能力,可以强制触发 GC,或者查询堆中某个类的实例列表。


---


7. 生产环境使用 Arthas 的注意事项


7.1 安全防护


Arthas 默认监听 8563 端口,仅允许本地 IP 127.0.0.1 连接。如果需要远程连接,建议通过堡垒机的 SSH 隧道转发,而不是直接开放端口。开放端口存在严重安全隐患,攻击者可以通过 Arthas 执行任意 OGNL 表达式,直接读取内存数据甚至修改运行时状态。


7.2 性能影响评估


Arthas 的字节码增强会为目标方法增加额外的执行指令。对于极高 QPS 的核心链路方法,使用 watch 命令时务必设置-n限制输出次数,并在排查完毕后通过stop命令移除增强,或者直接quit退出 Arthas。watch 命令在输出大量匹配结果时,I/O 操作会占用 JVM 线程资源。


7.3 快速卸载


Arthas 不会修改目标应用的代码文件,所有的增强仅在内存中生效。退出 Arthas 时执行stop命令,所有增强的类会被还原为原始字节码,不会残留任何修改。如果 Arthas 进程异常退出,增强的类会保持增强状态,但只是多执行一些空逻辑,不会影响业务正确性。


# 安全退出 Arthas,移除所有增强 stop


---


8. 实战案例:在线定位订单创建接口异常


背景:订单服务的createOrder接口间歇性返回 500 错误,错误日志中只记录了 NullPointerException,但没有具体的空指针位置和触发入参。


排查过程


第一步,使用 watch 命令开启异常捕获,等待问题复现:


watch com.example.service.OrderService createOrder '{params, throwExp}' -e -x 3 -n 1


几分钟后,Arthas 捕获到一次异常调用:


ts=2024-01-15 15:20:10; result=@ArrayList[ @Object[][ @Order[id=null,amount=500.0,userId=12345,itemList=null], ], java.lang.NullPointerException at com.example.service.OrderService.validateItems(OrderService.java:156) at com.example.service.OrderService.createOrder(OrderService.java:89) ]


问题一目了然:Order对象的itemList字段为 null,导致validateItems方法抛出空指针。进一步检查上游调用方,发现前端在某些场景下传入了空的商品列表。


如果没有 Arthas,排查这个问题的常规路径是:加日志记录入参 -> 提交代码 -> 构建 -> 部署 -> 等待复现 -> 看日志 -> 定位原因。整个周期至少需要一次发布流程。而 Arthas 将这个过程缩短为一条命令,耗时仅几分钟,且无需任何发布和重启。


耗时:数十分钟到数小时耗时:数分钟Arthas排查路径

发现异常

watch -e 抓取异常

直接看到入参和堆栈

修复代码

传统排查路径

发现异常

添加日志代码

提交 + 构建 + 部署

等待问题复现

查看日志定位

修复代码

修复上线

修复上线


watch 命令就像在代码中临时开了一扇窗户。不需要敲墙重装,只需轻轻一推,方法的内部世界便清晰可见。这是线上诊断中最高频、最实用的能力,也是对“重启加日志”这种传统方式的一次彻底告别。