十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

给 Java 开发者的线上诊断通关攻略 Arthas

给 Java 开发者的线上诊断通关攻略 Arthas 你有没有遇到过这种情况线上接口突然变慢本地复现不了CPU 莫名飙到 100%看了半天日志也没头绪或者某个方法返回值不对但日志根本没打印入参。以前遇到这些事要么加日志重新发版要么用jstack、jmap凑合看一眼。但这套流程又慢又粗糙等发版排完问题可能自己都消失了。Arthas 就是来解决这个问题的。它直接 attach 到运行中的 JVM 上让你看到方法入参、返回值、调用链路耗时甚至能反编译运行中的代码、热更新修 Bug——全程不用重启应用。这篇整理一下我日常用 Arthas 的完整流程从安装到实战一条龙走完。先说环境Arthas 本身是 Java 写的先确认机器上有 JDKjava -versionJDK 8 以上就行8 到 21 都支持。如果你的目标应用跑在 JDK 6/7 上得用 Arthas 3.x 的版本。然后得有一个正在跑的 Java 进程。没有的话可以用官方的演示程序curl -O https://arthas.aliyun.com/math-game.jar java -jar math-game.jar这个程序会在终端不断打印类似123453*5*823的东西说明它活着。安装就一行命令curl -O https://arthas.aliyun.com/arthas-boot.jar下载慢的话加个阿里云镜像java -jar arthas-boot.jar --repo-mirror aliyun如果你是 Linux 服务器也可以用脚本一键装curl -L https://arthas.aliyun.com/install.sh | sh装完会生成一个as.sh直接./as.sh就能启动。启动并连接到 Java 进程java -jar arthas-boot.jar它会列出当前所有的 Java 进程* [1]: 35542 [2]: 71560 math-game.jar输入序号回车就行。如果已经知道 PID也可以直接带上java -jar arthas-boot.jar 71560连接成功后会弹出一个 ASCII Art Logo看到它就说明 attach 上了。有个坑提一下启动 Arthas 的用户必须和目标进程是同一个用户不然 attach 不上。如果目标进程是 admin 跑的sudo -u admin -EH java -jar arthas-boot.jarattach 失败的话去看~/logs/arthas/下的日志。核心命令进入 Arthas 交互界面后先用help看看有哪些命令。我这里不列全量文档只说日常最常用的那几个。dashboard先看一眼全局dashboard相当于 Linux 的top一屏展示线程状态、内存使用、GC 情况。CtrlC退出刷新。第一眼看什么线程的%CPU列有没有特别高的内存的usage有没有快满的GC 次数有没有暴涨。先建立个整体印象再往下细查。threadCPU 飙高就靠这个排查 CPU 问题第一步永远是这个thread -n 3打印 CPU 占用最高的 3 个线程带完整堆栈。看完堆栈基本就知道是哪行代码在烧 CPU 了。如果应用卡死了不响应试试这个thread -b它会直接帮你找出那个持着锁、阻塞了其他线程的罪魁祸首。这个命令在排查死锁和阻塞问题时非常好用。想看某个具体线程的堆栈thread 1按状态过滤thread --state BLOCKED采样间隔可以调大一点结果更准(默认 200ms可以设成 1000ms)thread -n 3 -i 1000jad反编译运行中的代码有时候怀疑线上跑的不是最新代码或者根本拿不到源码直接反编译jad com.example.MyController只看某个方法jad com.example.MyController getUser只输出源码、不要 ClassLoader 信息jad --source-only com.example.MyController反编译出来的代码带语法高亮阅读体验还不错。如果发现一个类被多个 ClassLoader 加载了它会列出所有的 hashcode用-c指定具体哪个就行。sc / sm搜类和搜方法确认某个类有没有被加载sc com.example.*看详细信息(从哪个 jar 加载的、ClassLoader 是什么)sc -d com.example.MyController连成员变量一起看sc -d -f com.example.MyController看类里有哪些方法sm com.example.MyController小技巧异常堆栈里的类名是com/example/MyController这种斜杠分隔的直接丢给 sc 就行它会自动识别不用手动替换成点号。watch看方法的入参和返回值这大概是 Arthas 里用得最多的命令了。你想知道某个方法被调用时传了什么参数、返回了什么一行搞定watch com.example.MyController getUser {params, returnObj}-x控制展开深度默认只展开 1 层对象内部的内容看不到。设成 2 就能看到字段值了watch com.example.MyController getUser {params, returnObj} -x 2只看返回值watch com.example.MyController getUser returnObj加条件过滤比如只看耗时超过 200ms 的调用watch com.example.MyService processData {params, returnObj} #cost 200只看抛异常的情况watch com.example.MyService processData {params[0], throwExp} -e -x 2看当前对象(this)的属性watch com.example.MyService processData target.someField在方法执行前观察(此时还没有返回值)watch com.example.MyController getUser {params} -x 2 -b-n 2可以限制只执行两次就退出方便快速验证watch com.example.MyController getUser {params, target, returnObj} -x 2 -n 2trace方法内部每一步耗时多少watch看的是入参返回值trace看的是方法内部调了哪些子方法、各耗时多少。排查慢接口的时候非常有用。trace com.example.MyController getUser只跑一次就退出trace com.example.MyController getUser -n 1只看总耗时超过 10ms 的trace com.example.MyController getUser #cost 10默认不追踪 JDK 内部方法想看的话加上trace --skipJDKMethod false com.example.MyController getUser用正则匹配多个类和方法trace -E com.example.ClassA|com.example.ClassB method1|method2|method3需要注意trace 默认只追踪一层子调用。想深入多层的话3.3.0 之后支持动态 trace——在另一个终端telnet localhost 3658连上来用--listenerId指定就能继续往下钻。stack这个方法到底是被谁调用的有时候一个方法被执行了但不知道是谁触发的。stack打印调用路径stack com.example.MyService processRequest加条件stack com.example.MyService processRequest params[0] 0限制次数stack com.example.MyService processRequest -n 2monitor统计方法调用情况看一段时间内某方法的调用次数、成功失败次数、平均响应时间monitor com.example.MyController getUser -c 10-c 10表示每 10 秒统计一次。加条件也行monitor com.example.MyController getUser params[0] 100 -c 10注意 monitor 是通过字节码增强实现的用完记得reset或stop还原。logger不重启改日志级别线上出问题了想看 debug 日志但应用配的是 info又不能重启。改一下logger --name com.example --level debug排查完改回去logger --name com.example --level info整个操作几秒钟全程不重启。这个命令我在生产环境用过很多次了非常稳。vmtool翻内存里的对象 强制 GC查内存里某个类型有几个实例vmtool --action getInstances --className com.example.MyController --limit 5 -x 2强制 Full GCvmtool --action forceGcheapdump导出堆快照OOM 排查必备类似jmap -dumpheapdump --live /tmp/heapdump.hprof--live只导出可达对象文件更小。导出来用 MAT 或 JProfiler 打开分析。profiler生成火焰图CPU 性能问题的终极武器。先开始采样profiler start等个 30 秒左右停掉并生成火焰图profiler stop --file /tmp/flame.html用浏览器打开这个 HTML横轴越宽表示这个方法被采样到的次数越多(越耗 CPU)纵轴是调用栈深度。一眼就能看出瓶颈在哪。ognl直接执行表达式调用静态方法ognl java.lang.SystemcurrentTimeMillis()获取静态变量ognl com.example.MyConfigSOME_CONSTANT甚至能改私有字段(慎用)ognl #target com.example.MyConfigINSTANCE, #target.secretKey new-valuesysprop / sysenv查看和修改 JVM 系统属性、环境变量。查看所有sysprop查看某个sysprop java.version临时改一个(重启后失效)sysprop my.custom.property newValue热更新代码这个功能我觉得是 Arthas 最酷的地方。线上发现一个 Bug不想等发版流程可以直接热更新修复。基本流程是这样的第一步反编译目标类拿到当前运行中的源码jad --source-only com.example.BugController /tmp/BugController.java第二步编辑这个文件修掉 Bugvi /tmp/BugController.java第三步内存编译成 .classmc /tmp/BugController.java -d /tmp第四步加载到 JVMredefine /tmp/com/example/BugController.class第五步验证一下jad com.example.BugController watch com.example.BugController buggyMethod returnObj几个注意点热更新是临时的应用重启就恢复了所以正式发版不能省。另外只能改方法体不能加字段加方法。线上操作前务必先在测试环境跑一遍。几个实战场景把上面这些命令串起来看看实际遇到问题时的排查思路。CPU 飙到 100%java -jar arthas-boot.jar thread -n 3看堆栈定位到具体代码。如果一层不够用 trace 往下钻trace com.example.YourClass yourMethod还不行就上火焰图profiler start # 等 30 秒 profiler stop --file /tmp/cpu-flame.html接口卡死不响应thread -b先找出是谁拿着锁。然后看 BLOCKED 的线程thread --state BLOCKED拿到线程 ID 后看完整堆栈thread 27再用 trace 看卡在哪一步trace com.example.YourService yourMethod方法返回值不对watch com.example.YourService yourMethod {params, returnObj} -x 2看看每次调用的入参和返回值是什么。怀疑异常的话watch com.example.YourService yourMethod {params[0], throwExp} -e -x 2不确定代码是不是最新的jad --source-only com.example.YourController sc -d com.example.YourController看code-source字段就是 jar 包路径确认是不是预期的版本。OOM 内存泄漏heapdump --live /tmp/heapdump.hprof导出来用 MAT 分析。或者先看看内存里某个对象有多少实例vmtool --action getInstances --className com.example.YourObject --limit 100 memory偶发问题一天才出一次用后台任务挂着watch com.example.YourService rareMethod {params, returnObj} -x 2 jobs查看后台任务fg job_id拉到前台kill job_id终止。后台任务生命周期默认 1 天断开 session 也不影响。退出和清理退出当前连接(Arthas 服务端还在跑)quit完全停止 Arthas(所有增强过的类会被还原)stop只还原增强过的类不退出 Arthasreset com.example.MyController reset *彻底卸载rm -rf ~/.arthas/ rm -rf ~/logs/arthas/几个踩过的坑权限启动 Arthas 的用户和目标进程必须是同一个用户不然 attach 不上。性能开销watch、trace、monitor 这些命令通过字节码增强实现有性能开销。用的时候指定到具体的类和方法别用太宽的通配符。查完就reset或stop。热更新非持久redefine 的改动重启就没了该发版还得发版。端口安全Arthas 默认监听 3658 端口生产环境注意别暴露到公网可以配 auth 鉴权。trace 只有一层默认只追踪一层子调用多层需要用动态 trace。采样精度thread 的 CPU 采样有自身开销间隔太短不准建议设到 1000ms 以上。快捷键快捷键功能CtrlC中断当前命令CtrlD退出(等同 quit)Tab自动补全↑↓浏览历史命令CtrlR搜索历史命令写在最后Arthas 用熟了之后很多以前需要重启应用才能排查的问题现在几条命令就搞定了。尤其watchtracethread这三个组合覆盖了日常 80% 的诊断场景。建议平时拿官方的math-game演示程序练练手等线上真出问题的时候不至于手忙脚乱。官方文档在这里遇到具体参数问题随时查https://arthas.aliyun.com/doc
返回列表