ElIauk

Arthas 线上排查常用命令

Arthas 解决什么问题 线上接口突然变慢,日志里没有异常,重启后又恢复了。这种问题最难查:不能加日志重启,不能本地复现,只能对着一个正在运行的 JVM 猜。Arthas 通过 attach 机制挂到目标进程上,不重启、不改代码,就能看线程栈、方法耗时、入参返回值、类加载信息。 它的原理是动态 a

评论
Arthas 线上排查常用命令

Arthas 解决什么问题

线上接口突然变慢,日志里没有异常,重启后又恢复了。这种问题最难查:不能加日志重启,不能本地复现,只能对着一个正在运行的 JVM 猜。Arthas 通过 attach 机制挂到目标进程上,不重启、不改代码,就能看线程栈、方法耗时、入参返回值、类加载信息。

它的原理是动态 attach 到 JVM,利用 Instrumentation 做字节码增强。JDK 17 下 attach 机制仍然可用,但目标进程和 Arthas 必须用同一个用户启动,容器里还要注意 PID 命名空间。生产环境使用前要确认合规:Arthas 能读取方法参数和返回值,可能包含敏感数据,端口也不能直接暴露到公网。

命令地图

命令 用途
dashboard 总览线程、内存、GC、运行时
thread 查看线程栈、CPU 占用、死锁
jad 反编译已加载的类,确认线上代码版本
watch 观察方法入参、返回值、异常
trace 追踪方法内部调用耗时
monitor 周期性统计方法调用次数和耗时
stack 查看方法被谁调用
tt 记录调用现场,支持事后回放
sc / sm 查类、查方法
ognl 执行表达式,读取或修改对象
heapdump 导出堆转储
profiler 生成 CPU 火焰图

先启动:

curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar --telnet-port 3658 --http-port 8563

启动后会列出当前用户的 Java 进程,输入序号 attach。端口只监听本地时更安全,需要远程访问就用 SSH 隧道,不要把 3658 直接开到公网。

CPU 高与慢方法

CPU 飙高时,先用 dashboard 看整体,再按线程排序:

dashboard
thread -n 5
thread -b

thread -n 5 列出 CPU 占用最高的五个线程,拿到线程 ID 后再 thread <id> 看完整栈。thread -b 专门找阻塞其他线程的锁持有者,死锁和长时间等待用它最快。

接口慢但 CPU 不高,通常是 IO 或锁等待,用 trace 定位耗时落在哪个方法:

trace com.example.order.OrderService create '#cost > 200' -n 5

#cost > 200 表示只记录耗时超过 200 毫秒的调用,-n 5 表示最多记录五次。不加限制地 trace 高并发方法,字节码增强本身就会拖慢应用。需要看具体参数和返回值时用 watch:

watch com.example.order.OrderService create '{params, returnObj, throwExp}' -x 2 -n 5

-x 2 是展开层级,层级越大输出越多,也越容易把日志打爆。线上排查建议先用 trace 找到慢方法,再用 watch 看特定条件的数据,不要反过来。

几个典型场景

方法返回值不符合预期:用 watch 看入参和返回值,确认是参数传错、还是下游返回异常。如果问题偶发,用 tt -t 记录多次调用,事后用 tt -i <index> -p 回放,不用一直盯着终端。

类版本不对:线上跑的还是旧包,jad com.example.OrderService 反编译看实际字节码,再 sc -d com.example.OrderService 看类的加载器和来源路径。多版本 jar 冲突时,classloader -t 能看到类加载器的层级关系。

日志级别临时调整:logger --name com.example.order --level debug 可以在不重启的情况下打开调试日志,排查完记得改回去。修改是运行时生效的,进程重启后恢复配置值。

线程池满、连接池耗尽:thread 看线程状态和栈,monitor -c 5 com.example.DbService query 统计方法调用频率和平均耗时。再结合 vmtool --action getInstances --className com.zaxxer.hikari.HikariDataSource --limit 10 拿到数据源实例,看连接池状态。

常见坑

1. attach 失败

常见原因是用户不一致、目标进程开启了 -XX:+DisableAttachMechanism、容器里 PID 命名空间隔离、或者 /tmp 权限不对。容器环境要把宿主机的 /tmp 挂进去,或者用 jattach 指定 PID。JDK 17 不再需要单独找 tools.jar,但 JVM 必须是 HotSpot。

2. trace 和 watch 开销过大

这两个命令都会做字节码增强,方法调用越频繁,开销越明显。一定要加 -n 限制次数,加条件表达式缩小范围,排查完执行 stop 或 shutdown 卸载增强。不要在生产对 QPS 上万的方法长期开 trace。

3. tt 把内存打满

tt 会保存调用现场的对象引用,记录越多占用越大。用 -n 限制条数,排查完执行 tt --delete-all。堆本来就紧张时,先别用 tt。

4. ognl 改坏了线上状态

ognl 能调用任意方法、修改静态字段,等于在进程里执行代码。只读场景也可能触发懒加载或副作用。生产环境优先用 watch、trace 这类观察命令,确需修改时先确认影响范围。

5. 把 jad 的反编译结果当成源码

反编译是近似还原,泛型、lambda、编译器优化后的代码可能和源码不一致。jad 用来确认“线上到底是哪个版本”,不要拿它当源码提交。

6. heapdump 打满磁盘

一次 dump 的大小接近堆使用量,磁盘空间不够会失败,甚至影响业务。导出前确认目录空间,dump 文件包含业务数据,注意权限和脱敏。

排查步骤

一个可复用的顺序是:先看整体,再定位线程,然后追方法,最后看数据。

dashboard
thread -n 5
trace com.example.order.OrderController getOrder '#cost > 500' -n 5
watch com.example.order.OrderService getOrder '{params, returnObj, throwExp}' -x 2 -n 5
stop

CPU 高先看 thread,接口慢先看 trace,结果不对先看 watch,偶发问题用 tt。每一步都带着明确假设,不要把所有命令都开一遍。排查结束后务必 stop,确认增强类已经卸载,避免长期影响性能。

小结

Arthas 的价值是把“重启加日志”变成“在线观察”,但它不是银弹。它擅长定位“哪个方法慢、参数是什么、线程卡在哪”,不擅长替代监控和链路追踪。生产使用要有审批、有超时、有清理,观察命令优先于修改命令。

参考

评论

推荐阅读

订阅邮件

订阅更新,及时收到最新文章。

作者