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 3params表示方法的所有入参。returnObj表示方法的返回值。-x 3指定输出结果中对象的展开深度为 3 层。如果不指定展开深度,嵌套对象默认只显示第一层的引用地址。
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 24.3 追踪方法内部耗时
在观察表达式中可以使用#cost变量获取方法执行的总耗时:
# 输出方法入参和执行耗时 watch com.example.service.OrderService createOrder \ '{params, #cost}' 'params[0].amount > 10000' -x 2#cost是 Arthas 注入的特殊变量,表示当前调用从进入到返回的总耗时,单位毫秒。这对于定位慢请求非常有效。
---
5. 基于 Arthas 的线上问题排查完整流程
Arthas 的核心价值在于它提供了一个在线观察窗口。传统排查是“猜问题 - 加日志 - 重启 - 验证”的反复循环,而 Arthas 将这个过程变为“观察现象 - 定位根因 - 一次修复”。每一次省去的重启,都是对生产环境稳定性的保护。
---
6. Arthas 的其他常用命令速览
watch 命令解决的是方法级别的入参和返回值观察,但完整的线上诊断往往需要多个命令配合。
6.1 trace 命令:追踪方法内部调用路径与耗时
trace com.example.service.OrderService createOrdertrace 会输出createOrder方法内部所有子调用的耗时树形图,清晰展示每一层调用的时间占比。当 watch 确认了某个方法总体耗时异常后,trace 用来向下钻取具体的耗时点。
6.2 jad 命令:在线反编译源码
jad com.example.service.OrderService createOrderjad 直接反编译运行中的 class 文件,输出 Java 源码。这对于验证部署的代码版本是否正确、确认线上实际运行的逻辑非常有帮助。如果怀疑回滚未生效或代码未同步,jad 是最直接的验证工具。
6.3 tt 命令:方法执行数据时空隧道
tt -t com.example.service.OrderService createOrdertt 是 Time Tunnel 的缩写。它会记录方法每次调用的入参、返回值、异常、耗时等完整信息,并保存在一个时间碎片中。之后可以通过索引号随时回放某次调用的现场。tt 适合排查那些难以复现的偶发问题:先在线上开启记录,问题复现后再回放现场。
6.4 dashboard 命令:实时 JVM 监控面板
dashboarddashboard 输出一个实时刷新的 JVM 监控面板,包括线程使用情况、内存各区域占用、GC 次数和耗时、CPU 使用率等。这是接入 Arthas 后的第一个诊断动作,用于快速判断 JVM 的整体健康状态。
6.5 vmtool 命令:强制 GC 和内存分析
vmtool --action forceGc vmtool --action getInstances --className java.lang.String --limit 10vmtool 提供了对 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 将这个过程缩短为一条命令,耗时仅几分钟,且无需任何发布和重启。
watch 命令就像在代码中临时开了一扇窗户。不需要敲墙重装,只需轻轻一推,方法的内部世界便清晰可见。这是线上诊断中最高频、最实用的能力,也是对“重启加日志”这种传统方式的一次彻底告别。
