
在生产环境中,我们经常遇到这样的场景:接口突然变慢、偶发性异常、CPU飙升、内存泄漏等问题。传统的排查方式需要重新部署、添加日志,耗时费力。而 Arthas 作为阿里开源的 Java 诊断工具,可以在不重启应用的情况下,实时诊断线上问题。
本文将通过实战案例,带你掌握 Arthas 的核心功能,让生产问题排查事半功倍。
一、Arthas 快速入门
1.1 安装与启动
本地使用(可以正常联网的机器)
# 下载 arthas-boot.jar
curl -O https://arthas.aliyun.com/arthas-boot.jar
# 启动 Arthas
java -jar arthas-boot.jar
# 选择要诊断的 Java 进程,输入前面的数字
[1] 12345 com.example.Application
启动后,Arthas 会自动 attach 到目标进程,无需修改任何代码或重启应用。
离线环境,不可联网
如果是不可联网的内网环境,可以通过 github https://github.com/alibaba/arthas/releases 下载完整包
#
wget https://github.com/alibaba/arthas/releases/download/arthas-all-4.1.2/arthas-bin.zip
unzip arthas-bin.zip -d arthas
cd arthas
# linux、mac下使用 as.sh ,windows 下使用 as.bat
sh as.sh
# 选择要诊断的 Java 进程,输入前面的数字
[1] 12345 com.example.Application
启动后,Arthas 会自动 attach 到目标进程,无需修改任何代码或重启应用。
1.2 基础命令速览
# 查看 JVM 信息
dashboard
# 查看线程信息
thread
# 查看已加载的类
sc com.example.*
# 查看方法信息
sm com.example.UserService
二、接口性能问题排查
2.1 场景:接口响应变慢
问题描述:用户反馈订单查询接口从 100ms 变慢到 3 秒以上。
使用 trace 命令追踪方法调用链
trace com.example.OrderService queryOrder
输出示例:

分析结果:耗时集中在数据库查询,3200ms 占总耗时 99%。
深入追踪慢查询
# 追踪 SQL 执行
trace org.hibernate.query.Query getSingleResult -n 5
# 查看方法入参和返回值
watch com.example.OrderRepository findById '{params, returnObj}' -x 2
优化方向:
- 检查是否缺少索引
- 是否存在 N+1 查询问题
- 考虑添加缓存
2.2 场景:找出最耗时的方法
使用 monitor 命令监控方法调用统计:
monitor -c 5 com.example.OrderService queryOrder
输出示例:
timestamp class.method total success fail avg-rt(ms) fail-rate
2024-11-04 OrderService.queryOrder 156 148 8 2847.32 5.13%
分析:
- 失败率 5.13%,需要关注异常情况
- 平均响应时间 2.8 秒,确认性能瓶颈
三、异常问题排查
3.1 场景:接口偶发性报错
问题描述:用户支付接口偶尔抛出 NullPointerException,但日志不完整。
使用 watch 捕获异常
watch com.example.PaymentService processPay '{params, throwExp}' -e -x 2
参数说明:
-e:只在方法抛异常时输出-x 2:展开对象层级为 2 层
输出示例:
method=com.example.PaymentService.processPay
params=[@PaymentRequest[orderId=12345, amount=null, userId=678]]
throwExp=java.lang.NullPointerException: amount cannot be null
at com.example.PaymentService.processPay(PaymentService.java:45)
定位到问题:amount 字段为 null,需要在上游做参数校验。
3.2 查看异常发生时的完整上下文
# 捕获方法入参、返回值、异常及耗时
watch com.example.PaymentService processPay '{params, returnObj, throwExp, costMs}' -x 3 -n 5
3.3 追踪异常的根源
# 追踪调用链,找到异常最初来源
stack com.example.PaymentService processPay
输出:
ts=2024-11-04 10:30:12;thread_name=http-nio-8080-exec-5;
@com.example.PaymentController.pay()
at com.example.PaymentService.processPay()
at com.example.PaymentValidator.validate()
at com.example.AmountChecker.check()
四、实时查看源码与反编译
4.1 场景:线上代码与预期不符
问题描述:明明修复了 bug 重新部署,但问题依然存在。
使用 jad 反编译查看实际代码
jad com.example.OrderService queryOrder
输出:
public Order queryOrder(Long orderId) {
// 检查实际运行的代码逻辑
if (orderId == null) {
return null; // 😱 居然还是旧代码!新加的校验逻辑根本不在!
}
return orderRepository.findById(orderId);
}
发现问题:部署的 jar 包版本不对,或者类加载器加载了旧版本的类。
4.2 查看类的加载信息
# 查看类从哪个 jar 包加载
sc -d com.example.OrderService
# 输出示例
class-info:
class: com.example.OrderService
classLoaderHash: 2a3d9c5f
codeSource: /app/libs/order-service-1.0.0.jar
isInterface: false
4.3 对比不同版本的代码
# 反编译并保存到文件
jad --source-only com.example.OrderService > /tmp/OrderService_v1.java
# 部署新版本后再次对比
jad --source-only com.example.OrderService > /tmp/OrderService_v2.java
五、高级技巧:方法调用详细分析
5.1 查看方法的入参和返回值
# 查看所有参数和返回值
watch com.example.UserService findUser '{params, returnObj}' -x 3
# 条件过滤:只看 userId=1001 的调用
watch com.example.UserService findUser '{params, returnObj}' 'params[0]==1001' -x 3
5.2 统计方法调用成功率
# 每 5 秒统计一次
monitor -c 5 com.example.UserService findUser
5.3 获取方法调用时间分布
# 查看哪些调用超过 1 秒
trace com.example.UserService findUser '#cost > 1000'
六、生产环境最佳实践
6.1 性能影响最小化
# 限制监控次数,避免影响性能
trace com.example.OrderService queryOrder -n 10
# 设置条件过滤,减少输出
watch com.example.OrderService queryOrder '{params}' 'params[0] > 10000' -n 5
6.2 定位热点方法
# 找出 CPU 占用最高的线程
thread -n 3
# 查看具体线程的堆栈
thread 123
6.3 保存诊断结果
# 将输出重定向到文件
trace com.example.OrderService queryOrder > /tmp/trace_result.log
# 导出诊断报告
options json-format true
profiler start
profiler stop --format html --file /tmp/profile.html
七、常见问题与解决方案
7.1 Arthas 无法 attach 到进程
解决方案:
# 使用 root 权限
sudo java -jar arthas-boot.jar
# 或指定 PID
java -jar arthas-boot.jar <PID>
7.2 命令执行后无输出
原因:
- 方法没有被调用到
- 类名或方法名拼写错误
排查步骤:
# 1. 确认类已加载
sc com.example.OrderService
# 2. 确认方法存在
sm com.example.OrderService
# 3. 使用模糊匹配
trace com.example.*Service query*
7.3 输出内容被截断
# 增加展开层级
watch com.example.OrderService queryOrder '{params}' -x 4
# 设置输出行数
options unsafe true
八、实战案例总结
案例 1:接口 RT 突增
问题:订单查询接口响应时间从 100ms 飙升到 5 秒
排查步骤:
- 使用
trace追踪调用链,发现耗时在 Redis 连接超时 - 使用
thread查看线程堆栈,发现大量线程阻塞在 Redis 连接获取 - 检查 Redis 连接池配置,发现
maxTotal=5太小 - 调整连接池大小,问题解决
案例 2:偶发 NPE
问题:支付回调接口偶尔抛出 NullPointerException
排查步骤:
- 使用
watch -e捕获异常时的参数 - 发现某个上游服务返回的字段为 null
- 添加非空校验,问题解决
案例 3:新版本上线后功能异常
问题:修复的 bug 在线上依然复现
排查步骤:
- 使用
jad反编译查看实际代码 - 发现运行的是旧版本代码
- 检查 CI/CD 流程,发现打包时引用了旧依赖
- 重新打包部署,问题解决
九、命令速查表
| 命令 | 用途 | 示例 |
|---|---|---|
trace | 追踪方法调用链路 | trace com.example.Service method |
watch | 观察方法入参/返回值/异常 | watch com.example.Service method '{params, returnObj}' |
monitor | 统计方法调用 | monitor -c 5 com.example.Service method |
stack | 查看方法调用堆栈 | stack com.example.Service method |
jad | 反编译类 | jad com.example.Service |
sc | 查看类信息 | sc -d com.example.* |
sm | 查看方法信息 | sm com.example.Service |
thread | 查看线程信息 | thread -n 3 |
总结
Arthas 是 Java 开发者在生产环境排查问题的必备神器。通过本文介绍的场景和命令,你可以:
快速定位性能瓶颈:使用 trace 追踪方法耗时,精确到每一行代码
捕获异常根因:watch 命令实时捕获异常上下文,不放过任何细节
验证线上代码:jad 反编译确保运行的就是最新版本
零侵入式诊断:无需修改代码或重启服务,对业务影响降到最低
记住:工具用得好,下班下得早。赶紧在你的工具箱里装上 Arthas,让生产问题无处遁形!
关注公众号,获取更多 Java 性能优化与问题排查技巧!
参考资料:
- Arthas 官方文档:https://arthas.aliyun.com/
- Arthas GitHub:https://github.com/alibaba/arthas
Q.E.D.


