1. 线上监控工具 Arthas 到底是什么做后端开发这些年,最怕的不是写不出代码,而是线上环境出了诡异问题,日志却什么都看不出来。CPU 突然飙到 99%,接口偶尔超时,内存悄悄涨上去又降不下来,JVM 里跑的程序就像个黑盒——你只能靠猜。以前我的常规操作是:加日志、发版、观察,再不行就重启大法。但每次重启都会把现场破坏掉,问题复现不出来,只能干瞪眼。Arthas 就是来解决这个痛点的。它是阿里开源的一款 Java 诊断工具,不需要修改代码,不需要重启服务,直接附着到正在运行的 JVM 进程上,就能在线查看类加载信息、方法调用参数和返回值、异常堆栈、GC 情况、线程状态,甚至还能在线反编译线上代码、动态修改方法执行的逻辑。用一句话概括:让线上 JVM 变成透明的,想看哪里就看哪里。这款工具适合谁来用?说实话,只要你写 Java,都应该掌握。特别是做后端开发、中间件维护、以及负责线上问题排查的运维和 SRE 同学。它最亮眼的场景是:在一个正在运行的 Java 服务上,你怀疑某个方法执行慢,但不知道它处理了什么数据、卡在哪一行,这时候用 Arthas 的 trace 命令,不需要改代码,几秒钟就能看到方法内部每层调用的耗时分布。我第一次接触 Arthas 是两年前处理一个接口偶发超时的问题,当时排查了两天没结果,最后靠 trace 命令定位到一个第三方 SDK 的重试逻辑,问题当天就解决了。从那以后,Arthas 就常驻在我的工具箱里。1.1 Arthas 的核心价值在哪先说成本。相比其他监控方案,Arthas 最大的优势是零侵入。不需要在应用代码里埋点,不需要引入额外的 agent 依赖,不需要重启服务。它利用 Java 的 Instrumentation 机制,在运行时动态增强方法字节码,相当于给运行中的 JVM 装了一个后视镜和显微镜。再说效率。传统排查流程是“怀疑—加日志—发版—观察”,一次至少二十分钟。Arthas 是“attach—命令—看结果”,熟练之后一分钟内完成一次诊断。这种效率差距在故障处置时极其关键,特别是在大促、线上告警已经拉响的时候,快一分钟就能少损失很多。1.2 使用 Arthas 的前提条件目标进程必须是 Java 语言写的应用,运行在 JVM 上(Java 6 及以上版本都支持)。需要和目标是同一个操作系统用户,或者具备相应权限,否则会因权限不足无法 attach。运维安全策略上,通常建议在跳板机或堡垒机内执行,避免在公网直接暴露诊断端口,这个后面细说。2. Arthas 的下载安装与启动Arthas 的安装方式有好几种,我分成在线脚本安装、全量包下载、以及离线安装三种场景。很多人以为安装就是把 jar 包下载下来,其实它的启动逻辑和普通 Java 程序不太一样,先搞清楚这点,后面才不会踩坑。2.1 在线脚本安装(最快上手)在服务器上执行下面这行命令:curl -sL https://arthas.aliyun.com/install.sh | sh脚本执行完毕后,会在当前目录生成 arthas-bin 文件夹,里面包含了 arthas-boot.jar 和 as.sh 脚本。之后启动只需要运行:./as.sh这个脚本工具会列出当前机器上所有 Java 进程,输入序号回车就能连接。整个过程体验很顺,但有个小坑:如果服务器没有外网访问权限,脚本就会下载失败。很多公司的生产网段是隔离的,这时候就要用到下面两种方式。2.2 全量安装包方式(离线环境适用)从 GitHub Releases 页面下载 arthas-packaging 对应的 release 版本压缩包,传到服务器后解压即用。压缩包结构大致是这样的:arthas-bin/ ├── as.sh ├── arthas-boot.jar ├── arthas-client.jar ├── arthas-core.jar ├── arthas-agent.jar └── math-game.jar其中 as.sh 是启动脚本,arthas-boot.jar 是引导程序,真正干活的是 arthas-core 和 arthas-agent。math-game.jar 是官方提供的一个演示程序,用来模拟一个不断运行的 Java 进程,方便你练手。2.3 在本地 IDEA 里用 Arthas 诊断 Demo还有一种很常用的学习方式:在本地 IDEA 里启动一个 Java 项目,然后直接运行 as.sh。系统会找到本地正在运行的 Java 进程,选择对应 PID 就能连接。这时候 Arthas 会生成一个随机的 telnet 端口和 HTTP 端口,默认 telnet 端口是 3658,HTTP 端口是 8563。如果想要固定端口方便调试,可以带参数启动:./as.sh --telnet-port 9999 --http-port 9998这个参数在批量脚本化的场景里很有用,固定端口后就可以用客户端工具对接。不过要注意,端口固定可能造成冲突,如果同一个机器上有多个 Java 进程都要诊断,建议还是用随机端口省心,或者用不同的固定端口区分。2.4 启动时就遇到的常见问题执行 as.sh 后提示没有 Java 环境:检查 JAVA_HOME 是否配置正确,Arthas 需要 Java 6 以上。attach 指定的进程失败:最常见是权限不足,当前用户和 Java 进程的启动用户不一致,切换用户重试即可。提示端口被占用:要么杀掉占用进程,要么换一个端口启动。Mac 用户第一次使用可能会弹安全提示,需要在系统设置里允许终端访问;Windows 用户建议直接用 Git Bash 或者 WSL,原生 cmd 的兼容性差一些。3. 线上故障排查的核武器:五类高频命令实操安装成功只是开始,真正考验功力的是命令的选择和使用。Arthas 命令非常多,官方文档列了一长串,但实际工作中高频使用的基本集中在五个:dashboard、thread、jad、watch、trace。把这五个玩明白,90% 的线上问题都能找到方向。3.1 dashboard:全局概览,第一站必看连接上进程后,第一时间输入 dashboard,屏幕上会展示当前 JVM 的全局状况。主要分几个区块:线程列表:实时显示各个线程的状态、CPU 占用率,哪个线程在疯狂消耗 CPU 一眼就能看到。内存信息:堆内存各个区域的使用情况,包括 Eden、Survivor、Old 区分别占了多少,是否有明显压力。GC 统计:包括 GC 次数、耗时,以及最后一次 GC 的原因。运行环境信息:JVM 版本、Java 版本、操作系统等。我在实际诊断中,最常见的路径就是:先 dashboard 看全局,发现某个线程 CPU 占比异常高,然后切到 thread 命令看线程栈,定位卡在哪里。3.2 thread:线程诊断,定位死锁和热点thread 命令支持查看指定的线程信息,最常用的几个用法:# 查看 CPU 占用最高的前 N 个线程 thread -n 3 # 查看指定线程 ID 的详细栈信息 thread 42 # 找出死锁线程 thread -bCPU 飙升排查是 thread 命令最经典的场景。有一次线上服务 CPU 100%,我执行 thread -n 3,看到某个业务线程 CPU 占用 80% 以上,线程栈显示一直卡在某个 JSON 序列化方法里,进一步分析发现是日志框架在并发量大的时候反复序列化大对象,优化后问题迅速解决。注意:thread 命令看到的线程 ID 是 JVM 内部的线程 ID,并不是操作系统层面的 PID。如果需要在系统层面对照(比如用 top 命令查到的线程 PID),需要把 JVM 线程 ID 转成十六进制,这在一些复杂的 JVM 崩溃场景里特别有用。3.3 jad:线上反编译,不用再去猜代码很多线上问题,你怀疑代码逻辑不对,但本地代码和线上发布的版本不一定一致。jad 命令直接反编译 JVM 中实际加载的类,看看线上跑的到底是不是你以为的那份代码。jad com.example.service.OrderService # 只反编译某个方法 jad com.example.service.OrderService createOrder这个命令最常用的场景是排查“本地改了代码但线上没生效”的问题。还有一种更隐蔽的场景:通过字节码增强工具(比如 APM agent)动态修改了方法逻辑,反编译后能看出来实际执行逻辑和源码不一样。3.4 watch:观测方法入参和返回值watch 命令是观测方法级别的黑科技,它能在不破坏现场的情况下,看到某个方法被调用时的入参、返回值、异常信息。这个能力在排查“接口偶尔报错但日志没记录”的问题时特别有用。watch com.example.service.OrderService createOrder '{params, returnObj, throwExp}' -x 3参数说明:'{params, returnObj, throwExp}'表示要观察的内容,分别是入参、返回值、抛出的异常。-x 3表示展开结果的深度,防止对象层级太深导致内容截断。需要注意,watch 默认每次方法调用都会输出,生产环境下高并发接口要慎用,否则刷屏严重,建议加上-n参数限制观测次数:watch com.example.service.OrderService createOrder '{params, returnObj}' -n 5加上-n 5表示只观测前五次调用,输出完自动停止,可以有效控制影响。另外,如果方法调用频率极高,建议配合条件表达式使用,只观测特定参数的调用:watch com.example.service.OrderService createOrder '{params[0]}' 'params[0].orderId == 10086' -x 23.5 trace:链路耗时分析,慢接口的克星trace 命令是性能排查的王牌。它能展示一个方法内部每一层嵌套调用的耗时分布,一眼看出耗时到底花在哪个环节。trace com.example.service.OrderService createOrder执行后,只要 createOrder 方法被调用一次,就会输出类似这样的结果:`---ts=2024-01-15 10:00:00;thread_name=http-nio-8080-exec-3;id=42;is_daemon=true;priority=5;total=1234ms `---[817ms] com.example.client.InventoryClient.queryStock() `---[812ms] com.example.client.HttpClientUtil.execute() `---[800ms] java.net.SocketInputStream.read()从输出可以看到,外层方法总耗时 1234ms,其中 817ms 花在 InventoryClient.queryStock() 上,再往下拆是 HTTP 请求的 socket 读取 800ms。这就说明问题在网络 IO 上,而不是业务代码本身逻辑复杂。看到这个结果,排查方向瞬间就明确了。trace 也支持按耗时过滤,只显示超过阈值的调用:trace com.example.service.OrderService createOrder '#cost > 500'这条命令只输出耗时超过 500ms 的调用,在低概率偶发慢请求的场景里特别好用。4. 生产环境实战排查:一次内存问题的完整过程工具讲再多,不如完整走一遍实战。下面我用一个之前处理过的模拟项目 X 的内存问题,从发现问题到最终定位,完整体现 Arthas 的使用思路。4.1 现场情况某服务在压测时发现,持续压测两个小时后,JVM 堆内存占用持续走高且无法回落,接口响应越来越慢,老年代 GC 频繁触发 Full GC,但 Full GC 后内存回收效果很差。当时第一反应是内存泄漏。4.2 排查步骤第一步,连接到目标进程,输入 dashboard 观察内存分布。发现 Eden 区和 Survivor 区波动不大,但 Old 区占用曲线持续上升,Full GC 后 Old 区回收量很少,这基本可以确定老年代里存在大量存活对象,可能是大对象一直未被释放,也可能是对象引用链未断开。第二步,使用 heapdump 命令导出堆内存快照:heapdump --live /tmp/heap.hprof注意点:heapdump 触发一次 Full GC 后只保留存活对象导出,文件会比全量 dump 小很多,对线上影响较小。拿到 hprof 文件后,用 MAT 工具分析支配树,找出了持有大量对象实例的怀疑对象。第三步,用 trace 和 watch 进一步确认方法级行为。在压测链路的关键方法上做 trace,观察是否有异常的对象创建;同时在某个可疑的 Producer 方法上 watch,确认是哪些调用路径持续产生大对象。最终定位到问题:一个 Kafka 消费线程在处理消息时,把整个消息体的字节数组缓存在了一个 static Map 里,但 Map 的清理机制只针对处理成功的消息,处理失败的消息会一直堆积。修复后压测验证,内存曲线恢复平稳。4.3 这个案例说明什么Arthas 的价值不只是某个命令强,而是这些命令配合起来,组合成一个完整的排查链路:dashboard 看全局、thread 定位线程、heapdump 精确取堆、trace/watch 确认业务方法行为。从这个案例可以看到,工具本身只是一部分,排查思路和排查经验同样重要。遇到内存问题,不要急着猜代码,先用 dashboard 看内存分布现状,再用 heapdump 拿数据,最后配合业务知识定位,这个方法论是实战中验证过的高效路径。5. 高阶玩法与生产安全注意事项如果你已经熟练掌握了基础命令,有两点值得进阶的方向:Arthas Tunnel 远程管理和生产环境安全管控。5.1 Arthas Tunnel:远程管理多台机器真实的线上环境通常是多台机器组成的集群,每台机器都去手动执行 as.sh 会很低效。Arthas Tunnel 解决的就是这个痛点:一个中央 Server 作为代理,客户端机器的 Arthas agent 主动连接到 Tunnel Server 注册,开发者本地通过 Tunnel 客户端连接 Server,间接操作远端机器上的 Arthas。架构上大致是注册与寻址分离:Agent 启动时指定 tunnel-server 地址,客户端通过 Arthas Tunnel 控制台查看已注册的机器列表,选择目标机器后发起诊断。这套方案特别适合没有跳板机权限管理混乱的团队,既方便统一管理,也便于审计。部署方式支持 Docker 一键启动,也支持 jar 包方式手动部署。线上多环境统一接一个 Tunnel Server,可以极大减少重复登录不同机器的操作成本。这里要特别提醒,Arthas 的诊断能力是把双刃剑,所有操作一定要落到审计日志里。5.2 生产环境使用 Arthas 的安全原则生产环境使用 Arthas,最重要的不是功能有多强,而是安全边界清晰。以下几点是我在实践中的强制约定,供团队参考:禁止在未授权的服务上随意使用 Arthas,必须有明确的故障工单或演练计划。Arthas 连接端口默认随机生成,任何情况下不允许在公网暴露 telnet 端口和 HTTP 端口。通过 Tunnel 管理时,Tunnel Server 必须部署在内网,并加访问控制。操作前评估对目标进程的影响。大部分命令对业务线程影响极小,但 ognl 表达式、动态字节码增强等操作要极其谨慎,避免破坏修改导致线上故障。强烈建议在预发环境先验证命令的写法,再去生产执行。watch 和 trace 命令有条件过滤就先带上条件,避免产生大量输出刷屏。注意:生产环境诊断完成后,一定要执行 stop 命令退出 Arthas,避免 Agent 长期驻留在业务 JVM 里,造成额外的开销或者安全暴露面。5.3 Arthas 之后还能扩展什么Arthas 解决的是“单个 JVM 里的黑盒问题”,但线上的故障往往不止单机维度。我在实践中,一般会把它和 APM 链路追踪系统配合使用:APM 负责全局链路追踪和指标监控,Arthas 负责单机深入诊断。两者配合,一个管宏观,一个管微观。如果你用 Arthas 用熟了,还可以关注它的核心原理,也就是 JVM 字节码增强和 Instrumentation 机制。理解了这个原理,你再去看 SkyWalking 或者其他 Java Agent 的实现,会发现思路是相通的,技术水平会有明显提升。6. 常见问题速查与避坑指南整理一下我在各种环境下使用 Arthas 遇到过的典型问题,做成一个速查表给读者参考:问题现象可能原因解决办法as.sh 无法连接新启动的 Java 进程Java 版本过低或 attach 权限不足确认 Java 6+,切换为同用户执行watch 命令无输出类或方法名写错,或者目标方法未被调用先 sc 排查类是否加载,再核对方法签名trace 命令看不到方法内部调用方法本身没有调用其他类的方法,或 JDK 内部类默认不增强加--skipJDKMethod false参数dashboard 显示 CPU 统计不准确统计窗口太短,采样失真多观察几次再下结论,配合 top 命令对照heapdump 导出的文件过大dump 了全量对象而非存活对象加上--live参数只导出存活对象Arthas 占用端口冲突多开会话端口随机产生冲突指定固定端口或用-p指定 PID 连接ognl 表达式执行报错语法或类加载上下文问题先 jad 确认类完整限定名,再简化表达式测试连接生产环境被防火墙拦截端口未开放或随机端口不稳定使用 Tunnel 模式,由 Agent 主动外连补充一个很实用的技巧:Arthas 支持批处理脚本模式,可以把常用命令写成脚本文件,然后通过as.sh -f /path/to/script.arthas方式执行,适合例行巡检和标准排查流程。第一次用 Arthas 的读者建议从官方提供的 math-game 演示程序开始练习。它是一个模拟的 Java 程序,会不断执行加减乘除运算,用 Arthas 可以实时观察方法入参、返回值、执行耗时,非常适合没有生产环境的同学快速入门。6.1 一个常被忽略的学习路径很多初学者喜欢把 Arthas 官方文档从头读到尾,读完后反而不知道该在什么场景下用哪个命令。我的学习建议是:不要背命令,要背场景。症状是 CPU 高,对应的就是 thread + dashboard症状是接口慢,对应的就是 trace症状是结果不对,对应的就是 watch 和 jad症状是内存异常,对应的就是 dashboard + heapdump症状是服务假死,对应的就是 thread -b 查死锁,以及 thread 查 BLOCKED 状态把场景和命令对应起来之后,遇到问题自然就知道该执行什么,这才是 Arthas 的正确打开方式。我自己带过不少新人,用这种“场景驱动”的方式学习,上手速度明显比死记命令更快。从实际经验来看,Arthas 装一遍五分钟,熟练掌握高频命令大概需要一到两周的实战积累。平时可以多在自己负责的服务上观察 dashboard 数据,熟悉健康状态下各项指标的基准范围,真正出问题时才能第一时间发现异常信号。这个习惯,比任何命令手册都管用。
1. 线上监控工具 Arthas 到底是什么做后端开发这些年,最怕的不是写不出代码,而是线上环境出了诡异问题,日志却什么都看不出来。CPU 突然飙到 99%,接口偶尔超时,内存悄悄涨上去又降不下来,JVM 里跑的程序就像个黑盒——你只能靠猜。以前我的常规操作是:加日志、发版、观察,再不行就重启大法。但每次重启都会把现场破坏掉,问题复现不出来,只能干瞪眼。Arthas 就是来解决这个痛点的。它是阿里开源的一款 Java 诊断工具,不需要修改代码,不需要重启服务,直接附着到正在运行的 JVM 进程上,就能在线查看类加载信息、方法调用参数和返回值、异常堆栈、GC 情况、线程状态,甚至还能在线反编译线上代码、动态修改方法执行的逻辑。用一句话概括:让线上 JVM 变成透明的,想看哪里就看哪里。这款工具适合谁来用?说实话,只要你写 Java,都应该掌握。特别是做后端开发、中间件维护、以及负责线上问题排查的运维和 SRE 同学。它最亮眼的场景是:在一个正在运行的 Java 服务上,你怀疑某个方法执行慢,但不知道它处理了什么数据、卡在哪一行,这时候用 Arthas 的 trace 命令,不需要改代码,几秒钟就能看到方法内部每层调用的耗时分布。我第一次接触 Arthas 是两年前处理一个接口偶发超时的问题,当时排查了两天没结果,最后靠 trace 命令定位到一个第三方 SDK 的重试逻辑,问题当天就解决了。从那以后,Arthas 就常驻在我的工具箱里。1.1 Arthas 的核心价值在哪先说成本。相比其他监控方案,Arthas 最大的优势是零侵入。不需要在应用代码里埋点,不需要引入额外的 agent 依赖,不需要重启服务。它利用 Java 的 Instrumentation 机制,在运行时动态增强方法字节码,相当于给运行中的 JVM 装了一个后视镜和显微镜。再说效率。传统排查流程是“怀疑—加日志—发版—观察”,一次至少二十分钟。Arthas 是“attach—命令—看结果”,熟练之后一分钟内完成一次诊断。这种效率差距在故障处置时极其关键,特别是在大促、线上告警已经拉响的时候,快一分钟就能少损失很多。1.2 使用 Arthas 的前提条件目标进程必须是 Java 语言写的应用,运行在 JVM 上(Java 6 及以上版本都支持)。需要和目标是同一个操作系统用户,或者具备相应权限,否则会因权限不足无法 attach。运维安全策略上,通常建议在跳板机或堡垒机内执行,避免在公网直接暴露诊断端口,这个后面细说。2. Arthas 的下载安装与启动Arthas 的安装方式有好几种,我分成在线脚本安装、全量包下载、以及离线安装三种场景。很多人以为安装就是把 jar 包下载下来,其实它的启动逻辑和普通 Java 程序不太一样,先搞清楚这点,后面才不会踩坑。2.1 在线脚本安装(最快上手)在服务器上执行下面这行命令:curl -sL https://arthas.aliyun.com/install.sh | sh脚本执行完毕后,会在当前目录生成 arthas-bin 文件夹,里面包含了 arthas-boot.jar 和 as.sh 脚本。之后启动只需要运行:./as.sh这个脚本工具会列出当前机器上所有 Java 进程,输入序号回车就能连接。整个过程体验很顺,但有个小坑:如果服务器没有外网访问权限,脚本就会下载失败。很多公司的生产网段是隔离的,这时候就要用到下面两种方式。2.2 全量安装包方式(离线环境适用)从 GitHub Releases 页面下载 arthas-packaging 对应的 release 版本压缩包,传到服务器后解压即用。压缩包结构大致是这样的:arthas-bin/ ├── as.sh ├── arthas-boot.jar ├── arthas-client.jar ├── arthas-core.jar ├── arthas-agent.jar └── math-game.jar其中 as.sh 是启动脚本,arthas-boot.jar 是引导程序,真正干活的是 arthas-core 和 arthas-agent。math-game.jar 是官方提供的一个演示程序,用来模拟一个不断运行的 Java 进程,方便你练手。2.3 在本地 IDEA 里用 Arthas 诊断 Demo还有一种很常用的学习方式:在本地 IDEA 里启动一个 Java 项目,然后直接运行 as.sh。系统会找到本地正在运行的 Java 进程,选择对应 PID 就能连接。这时候 Arthas 会生成一个随机的 telnet 端口和 HTTP 端口,默认 telnet 端口是 3658,HTTP 端口是 8563。如果想要固定端口方便调试,可以带参数启动:./as.sh --telnet-port 9999 --http-port 9998这个参数在批量脚本化的场景里很有用,固定端口后就可以用客户端工具对接。不过要注意,端口固定可能造成冲突,如果同一个机器上有多个 Java 进程都要诊断,建议还是用随机端口省心,或者用不同的固定端口区分。2.4 启动时就遇到的常见问题执行 as.sh 后提示没有 Java 环境:检查 JAVA_HOME 是否配置正确,Arthas 需要 Java 6 以上。attach 指定的进程失败:最常见是权限不足,当前用户和 Java 进程的启动用户不一致,切换用户重试即可。提示端口被占用:要么杀掉占用进程,要么换一个端口启动。Mac 用户第一次使用可能会弹安全提示,需要在系统设置里允许终端访问;Windows 用户建议直接用 Git Bash 或者 WSL,原生 cmd 的兼容性差一些。3. 线上故障排查的核武器:五类高频命令实操安装成功只是开始,真正考验功力的是命令的选择和使用。Arthas 命令非常多,官方文档列了一长串,但实际工作中高频使用的基本集中在五个:dashboard、thread、jad、watch、trace。把这五个玩明白,90% 的线上问题都能找到方向。3.1 dashboard:全局概览,第一站必看连接上进程后,第一时间输入 dashboard,屏幕上会展示当前 JVM 的全局状况。主要分几个区块:线程列表:实时显示各个线程的状态、CPU 占用率,哪个线程在疯狂消耗 CPU 一眼就能看到。内存信息:堆内存各个区域的使用情况,包括 Eden、Survivor、Old 区分别占了多少,是否有明显压力。GC 统计:包括 GC 次数、耗时,以及最后一次 GC 的原因。运行环境信息:JVM 版本、Java 版本、操作系统等。我在实际诊断中,最常见的路径就是:先 dashboard 看全局,发现某个线程 CPU 占比异常高,然后切到 thread 命令看线程栈,定位卡在哪里。3.2 thread:线程诊断,定位死锁和热点thread 命令支持查看指定的线程信息,最常用的几个用法:# 查看 CPU 占用最高的前 N 个线程 thread -n 3 # 查看指定线程 ID 的详细栈信息 thread 42 # 找出死锁线程 thread -bCPU 飙升排查是 thread 命令最经典的场景。有一次线上服务 CPU 100%,我执行 thread -n 3,看到某个业务线程 CPU 占用 80% 以上,线程栈显示一直卡在某个 JSON 序列化方法里,进一步分析发现是日志框架在并发量大的时候反复序列化大对象,优化后问题迅速解决。注意:thread 命令看到的线程 ID 是 JVM 内部的线程 ID,并不是操作系统层面的 PID。如果需要在系统层面对照(比如用 top 命令查到的线程 PID),需要把 JVM 线程 ID 转成十六进制,这在一些复杂的 JVM 崩溃场景里特别有用。3.3 jad:线上反编译,不用再去猜代码很多线上问题,你怀疑代码逻辑不对,但本地代码和线上发布的版本不一定一致。jad 命令直接反编译 JVM 中实际加载的类,看看线上跑的到底是不是你以为的那份代码。jad com.example.service.OrderService # 只反编译某个方法 jad com.example.service.OrderService createOrder这个命令最常用的场景是排查“本地改了代码但线上没生效”的问题。还有一种更隐蔽的场景:通过字节码增强工具(比如 APM agent)动态修改了方法逻辑,反编译后能看出来实际执行逻辑和源码不一样。3.4 watch:观测方法入参和返回值watch 命令是观测方法级别的黑科技,它能在不破坏现场的情况下,看到某个方法被调用时的入参、返回值、异常信息。这个能力在排查“接口偶尔报错但日志没记录”的问题时特别有用。watch com.example.service.OrderService createOrder '{params, returnObj, throwExp}' -x 3参数说明:'{params, returnObj, throwExp}'表示要观察的内容,分别是入参、返回值、抛出的异常。-x 3表示展开结果的深度,防止对象层级太深导致内容截断。需要注意,watch 默认每次方法调用都会输出,生产环境下高并发接口要慎用,否则刷屏严重,建议加上-n参数限制观测次数:watch com.example.service.OrderService createOrder '{params, returnObj}' -n 5加上-n 5表示只观测前五次调用,输出完自动停止,可以有效控制影响。另外,如果方法调用频率极高,建议配合条件表达式使用,只观测特定参数的调用:watch com.example.service.OrderService createOrder '{params[0]}' 'params[0].orderId == 10086' -x 23.5 trace:链路耗时分析,慢接口的克星trace 命令是性能排查的王牌。它能展示一个方法内部每一层嵌套调用的耗时分布,一眼看出耗时到底花在哪个环节。trace com.example.service.OrderService createOrder执行后,只要 createOrder 方法被调用一次,就会输出类似这样的结果:`---ts=2024-01-15 10:00:00;thread_name=http-nio-8080-exec-3;id=42;is_daemon=true;priority=5;total=1234ms `---[817ms] com.example.client.InventoryClient.queryStock() `---[812ms] com.example.client.HttpClientUtil.execute() `---[800ms] java.net.SocketInputStream.read()从输出可以看到,外层方法总耗时 1234ms,其中 817ms 花在 InventoryClient.queryStock() 上,再往下拆是 HTTP 请求的 socket 读取 800ms。这就说明问题在网络 IO 上,而不是业务代码本身逻辑复杂。看到这个结果,排查方向瞬间就明确了。trace 也支持按耗时过滤,只显示超过阈值的调用:trace com.example.service.OrderService createOrder '#cost > 500'这条命令只输出耗时超过 500ms 的调用,在低概率偶发慢请求的场景里特别好用。4. 生产环境实战排查:一次内存问题的完整过程工具讲再多,不如完整走一遍实战。下面我用一个之前处理过的模拟项目 X 的内存问题,从发现问题到最终定位,完整体现 Arthas 的使用思路。4.1 现场情况某服务在压测时发现,持续压测两个小时后,JVM 堆内存占用持续走高且无法回落,接口响应越来越慢,老年代 GC 频繁触发 Full GC,但 Full GC 后内存回收效果很差。当时第一反应是内存泄漏。4.2 排查步骤第一步,连接到目标进程,输入 dashboard 观察内存分布。发现 Eden 区和 Survivor 区波动不大,但 Old 区占用曲线持续上升,Full GC 后 Old 区回收量很少,这基本可以确定老年代里存在大量存活对象,可能是大对象一直未被释放,也可能是对象引用链未断开。第二步,使用 heapdump 命令导出堆内存快照:heapdump --live /tmp/heap.hprof注意点:heapdump 触发一次 Full GC 后只保留存活对象导出,文件会比全量 dump 小很多,对线上影响较小。拿到 hprof 文件后,用 MAT 工具分析支配树,找出了持有大量对象实例的怀疑对象。第三步,用 trace 和 watch 进一步确认方法级行为。在压测链路的关键方法上做 trace,观察是否有异常的对象创建;同时在某个可疑的 Producer 方法上 watch,确认是哪些调用路径持续产生大对象。最终定位到问题:一个 Kafka 消费线程在处理消息时,把整个消息体的字节数组缓存在了一个 static Map 里,但 Map 的清理机制只针对处理成功的消息,处理失败的消息会一直堆积。修复后压测验证,内存曲线恢复平稳。4.3 这个案例说明什么Arthas 的价值不只是某个命令强,而是这些命令配合起来,组合成一个完整的排查链路:dashboard 看全局、thread 定位线程、heapdump 精确取堆、trace/watch 确认业务方法行为。从这个案例可以看到,工具本身只是一部分,排查思路和排查经验同样重要。遇到内存问题,不要急着猜代码,先用 dashboard 看内存分布现状,再用 heapdump 拿数据,最后配合业务知识定位,这个方法论是实战中验证过的高效路径。5. 高阶玩法与生产安全注意事项如果你已经熟练掌握了基础命令,有两点值得进阶的方向:Arthas Tunnel 远程管理和生产环境安全管控。5.1 Arthas Tunnel:远程管理多台机器真实的线上环境通常是多台机器组成的集群,每台机器都去手动执行 as.sh 会很低效。Arthas Tunnel 解决的就是这个痛点:一个中央 Server 作为代理,客户端机器的 Arthas agent 主动连接到 Tunnel Server 注册,开发者本地通过 Tunnel 客户端连接 Server,间接操作远端机器上的 Arthas。架构上大致是注册与寻址分离:Agent 启动时指定 tunnel-server 地址,客户端通过 Arthas Tunnel 控制台查看已注册的机器列表,选择目标机器后发起诊断。这套方案特别适合没有跳板机权限管理混乱的团队,既方便统一管理,也便于审计。部署方式支持 Docker 一键启动,也支持 jar 包方式手动部署。线上多环境统一接一个 Tunnel Server,可以极大减少重复登录不同机器的操作成本。这里要特别提醒,Arthas 的诊断能力是把双刃剑,所有操作一定要落到审计日志里。5.2 生产环境使用 Arthas 的安全原则生产环境使用 Arthas,最重要的不是功能有多强,而是安全边界清晰。以下几点是我在实践中的强制约定,供团队参考:禁止在未授权的服务上随意使用 Arthas,必须有明确的故障工单或演练计划。Arthas 连接端口默认随机生成,任何情况下不允许在公网暴露 telnet 端口和 HTTP 端口。通过 Tunnel 管理时,Tunnel Server 必须部署在内网,并加访问控制。操作前评估对目标进程的影响。大部分命令对业务线程影响极小,但 ognl 表达式、动态字节码增强等操作要极其谨慎,避免破坏修改导致线上故障。强烈建议在预发环境先验证命令的写法,再去生产执行。watch 和 trace 命令有条件过滤就先带上条件,避免产生大量输出刷屏。注意:生产环境诊断完成后,一定要执行 stop 命令退出 Arthas,避免 Agent 长期驻留在业务 JVM 里,造成额外的开销或者安全暴露面。5.3 Arthas 之后还能扩展什么Arthas 解决的是“单个 JVM 里的黑盒问题”,但线上的故障往往不止单机维度。我在实践中,一般会把它和 APM 链路追踪系统配合使用:APM 负责全局链路追踪和指标监控,Arthas 负责单机深入诊断。两者配合,一个管宏观,一个管微观。如果你用 Arthas 用熟了,还可以关注它的核心原理,也就是 JVM 字节码增强和 Instrumentation 机制。理解了这个原理,你再去看 SkyWalking 或者其他 Java Agent 的实现,会发现思路是相通的,技术水平会有明显提升。6. 常见问题速查与避坑指南整理一下我在各种环境下使用 Arthas 遇到过的典型问题,做成一个速查表给读者参考:问题现象可能原因解决办法as.sh 无法连接新启动的 Java 进程Java 版本过低或 attach 权限不足确认 Java 6+,切换为同用户执行watch 命令无输出类或方法名写错,或者目标方法未被调用先 sc 排查类是否加载,再核对方法签名trace 命令看不到方法内部调用方法本身没有调用其他类的方法,或 JDK 内部类默认不增强加--skipJDKMethod false参数dashboard 显示 CPU 统计不准确统计窗口太短,采样失真多观察几次再下结论,配合 top 命令对照heapdump 导出的文件过大dump 了全量对象而非存活对象加上--live参数只导出存活对象Arthas 占用端口冲突多开会话端口随机产生冲突指定固定端口或用-p指定 PID 连接ognl 表达式执行报错语法或类加载上下文问题先 jad 确认类完整限定名,再简化表达式测试连接生产环境被防火墙拦截端口未开放或随机端口不稳定使用 Tunnel 模式,由 Agent 主动外连补充一个很实用的技巧:Arthas 支持批处理脚本模式,可以把常用命令写成脚本文件,然后通过as.sh -f /path/to/script.arthas方式执行,适合例行巡检和标准排查流程。第一次用 Arthas 的读者建议从官方提供的 math-game 演示程序开始练习。它是一个模拟的 Java 程序,会不断执行加减乘除运算,用 Arthas 可以实时观察方法入参、返回值、执行耗时,非常适合没有生产环境的同学快速入门。6.1 一个常被忽略的学习路径很多初学者喜欢把 Arthas 官方文档从头读到尾,读完后反而不知道该在什么场景下用哪个命令。我的学习建议是:不要背命令,要背场景。症状是 CPU 高,对应的就是 thread + dashboard症状是接口慢,对应的就是 trace症状是结果不对,对应的就是 watch 和 jad症状是内存异常,对应的就是 dashboard + heapdump症状是服务假死,对应的就是 thread -b 查死锁,以及 thread 查 BLOCKED 状态把场景和命令对应起来之后,遇到问题自然就知道该执行什么,这才是 Arthas 的正确打开方式。我自己带过不少新人,用这种“场景驱动”的方式学习,上手速度明显比死记命令更快。从实际经验来看,Arthas 装一遍五分钟,熟练掌握高频命令大概需要一到两周的实战积累。平时可以多在自己负责的服务上观察 dashboard 数据,熟悉健康状态下各项指标的基准范围,真正出问题时才能第一时间发现异常信号。这个习惯,比任何命令手册都管用。