本文最后更新于 1 分钟前,文中所描述的信息可能已发生改变。
Arthas(阿尔萨斯)是阿里巴巴开源的一款Java应用诊断利器,它能够帮助开发人员直接在线上环境定位问题,无需修改代码或重启应用。本文将全面介绍Arthas的核心功能和实际应用场景,帮助开发者掌握这一强大的诊断工具。
Arthas简介
什么是Arthas
Arthas是一款开源的Java应用诊断工具,由阿里巴巴于2018年9月开源。作为一个Java应用诊断利器,它允许开发者在不重启、不修改代码的情况下,实时诊断线上应用的各种问题:
- 实时查看JVM运行状态
- 监控方法执行情况
- 查看类加载信息
- 查看调用堆栈
- 热更新Java代码
- 线程分析与诊断
Arthas基于Greys工具进行了重构和增强,采用命令行交互模式,提供了丰富的命令用于问题排查和性能调优。
为什么需要Arthas
在Java应用线上运行时,我们可能会遇到各种问题:
- 应用卡顿,但无法确定是哪个方法耗时长
- 内存泄漏,但不知道是哪些对象占用内存
- 线程死锁或线程池满,但无法直接查看线程状态
- 方法调用异常,但无法确定参数值
- 代码逻辑有bug,但修复后需要重启应用
传统的解决方案通常是添加日志、远程调试或重启应用,这些方法要么侵入性强,要么会影响线上服务。Arthas的出现很好地解决了这些问题,让线上问题排查变得优雅和高效。
安装与启动
安装Arthas
Arthas提供了多种安装方式,最常用的是通过下载安装包安装:
# 下载Arthas安装包
curl -O https://arthas.aliyun.com/arthas-boot.jar
# 或使用wget
wget https://arthas.aliyun.com/arthas-boot.jar
其他安装方式:
- 通过Maven仓库下载:
<dependency>
<groupId>com.taobao.arthas</groupId>
<artifactId>arthas-packaging</artifactId>
<version>最新版本</version>
<type>tar.gz</type>
</dependency>
- 通过Docker使用:
docker run --rm -it --name arthas-demo arthas/arthas-demo
启动Arthas
下载完成后,可以通过以下命令启动Arthas:
# 启动Arthas
java -jar arthas-boot.jar
# 启动后会列出所有Java进程
# 输入应用对应的序号进行连接
启动后,Arthas会列出当前系统中所有的Java进程:
[INFO] arthas-boot version: 3.5.5
[INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.
* [1]: 12345 com.example.MyApplication
[2]: 23456 org.apache.catalina.startup.Bootstrap
输入对应的序号并回车,即可连接到指定的Java进程。
远程连接
Arthas支持远程连接模式,可以在一台机器上启动Arthas,然后在另一台机器上连接:
# 在服务器上启动Arthas并开启远程连接
java -jar arthas-boot.jar --target-ip 0.0.0.0 --telnet-port 9998 --http-port 8563
# 在另一台机器上通过telnet连接
telnet 服务器IP 9998
# 或者通过浏览器访问Web控制台
http://服务器IP:8563
Arthas核心功能详解
基础命令
先来了解一些基础命令,帮助我们熟悉Arthas环境:
- help:查看命令帮助信息
help
- cls:清空屏幕
cls
- session:查看当前会话信息
session
- reset:重置增强类,清除所有的增强
reset
- version:查看Arthas版本号
version
- quit/exit:退出Arthas客户端
quit
- shutdown:关闭Arthas服务端
shutdown
JVM相关命令
dashboard - 系统实时数据面板
dashboard命令可以显示当前系统的实时数据面板,包括线程、内存、GC等信息:
dashboard
输出示例:
ID NAME GROUP STATE %CPU DAEMON
-1 VM Periodic Task Thread - RUNNABLE 0.0 true
1 main main RUNNABLE 0.0 false
2 Reference Handler system WAITING 0.0 true
3 Finalizer system WAITING 0.0 true
...
Memory used total max usage
heap 32M 256M 4G 1.56%
ps_eden_space 14M 64M 1G 21.88%
ps_survivor_space 4M 16M 16M 25.00%
ps_old_gen 12M 176M 3G 0.59%
...
GC count time
MarkSweepCompact 0 0
Copy 0 0
...
jvm - JVM信息
jvm命令可以查看当前JVM的详细信息:
jvm
输出包括:
- Java版本
- JVM参数
- ClassLoader数量
- 线程数量
- 内存使用情况
- 操作系统信息等
thread - 线程相关信息
thread命令用于查看当前JVM的线程堆栈信息:
# 显示所有线程信息
thread
# 显示指定线程的堆栈
thread 线程ID
# 查找占用CPU最高的前3个线程
thread -n 3
# 查看死锁线程
thread -b
# 查看指定状态的线程
thread -state BLOCKED
memory - 内存信息
memory命令用于查看JVM内存信息:
memory
sysprop - 系统属性
sysprop命令用于查看或修改系统属性:
# 查看所有系统属性
sysprop
# 查看指定系统属性
sysprop java.version
# 修改系统属性
sysprop user.timezone Asia/Shanghai
sysenv - 环境变量
sysenv命令用于查看系统环境变量:
# 查看所有环境变量
sysenv
# 查看指定环境变量
sysenv PATH
vmoption - 虚拟机选项
vmoption命令用于查看和修改JVM参数:
# 查看所有虚拟机参数
vmoption
# 查看指定参数
vmoption PrintGC
# 修改参数
vmoption PrintGC true
heapdump - 堆转储
heapdump命令可以生成堆转储文件,用于分析内存问题:
# 生成堆转储文件
heapdump /tmp/dump.hprof
类和方法相关命令
sc - 查找类
sc (Search Class) 命令用于查找加载的类:
# 查找指定名称的类
sc com.example.MyClass
# 使用正则表达式查找类
sc com.example.*Service
# 查看类的详细信息
sc -d com.example.MyClass
sm - 查找方法
sm (Search Method) 命令用于查找类中的方法:
# 查找类中的方法
sm com.example.MyClass
# 查找指定方法
sm com.example.MyClass myMethod
# 查看方法的详细信息
sm -d com.example.MyClass myMethod
jad - 反编译
jad命令用于反编译指定的类:
# 反编译类
jad com.example.MyClass
# 反编译指定方法
jad com.example.MyClass myMethod
# 保存反编译结果到文件
jad --source-only com.example.MyClass > MyClass.java
mc - 内存编译
mc (Memory Compiler) 命令用于将.java文件编译成.class文件:
# 编译指定的Java文件
mc /tmp/MyClass.java
# 指定输出目录
mc -d /tmp/output /tmp/MyClass.java
redefine - 热更新
redefine命令用于重新加载类定义,实现不重启应用的Java代码热更新:
# 重新加载类
redefine /tmp/MyClass.class
热更新的典型流程:
- 使用
jad
命令反编译类到文件 - 修改Java文件
- 使用
mc
命令编译修改后的Java文件 - 使用
redefine
命令加载新的字节码
监控和诊断命令
monitor - 方法监控
monitor命令用于监控方法的执行情况:
# 监控方法的调用情况
monitor -c 5 com.example.MyClass myMethod
# 监控并设置条件表达式
monitor -c 5 -x 'params[0] > 0' com.example.MyClass myMethod
示例输出:
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 36 ms, listenerId: 1
timestamp class method total success fail avg-rt(ms) fail-rate
-------------------------------------------------------------------------------------------------------------
2022-01-01 12:00:00 com.example.MyClass myMethod 10 10 0 5.0 0.00%
2022-01-01 12:00:05 com.example.MyClass myMethod 18 18 0 4.5 0.00%
watch - 方法监听
watch命令用于监听方法的执行数据,如入参、返回值、异常等:
# 监听方法的返回值
watch com.example.MyClass myMethod '{params, returnObj}'
# 监听方法入参和异常
watch com.example.MyClass myMethod '{params, throwExp}' -e
# 监听方法调用前、后、异常和完成时
watch com.example.MyClass myMethod '{params, target, returnObj}' -x 3 -b -e -s -f
参数说明:
-b
在方法调用前监听-e
在方法异常时监听-s
在方法返回时监听-f
在方法结束时监听(正常返回或异常返回)-x
指定输出结果的展开层数
trace - 方法调用追踪
trace命令用于追踪方法内部的调用路径和每个调用的耗时:
# 追踪方法调用
trace com.example.MyClass myMethod
# 设置最大追踪深度
trace -n 3 com.example.MyClass myMethod
# 根据耗时过滤
trace com.example.MyClass myMethod '#cost > 10'
示例输出:
`---ts=2022-01-01 12:00:00;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@18b4aac2
`---[5.0ms] com.example.MyClass:myMethod()
+---[0.5ms] com.example.MyClass:methodA()
+---[3.0ms] com.example.MyClass:methodB()
| `---[2.5ms] com.example.MyClass:methodC()
`---[1.0ms] com.example.MyClass:methodD()
stack - 调用栈跟踪
stack命令用于输出当前方法被调用的路径:
# 跟踪方法的调用栈
stack com.example.MyClass myMethod
# 设置最大深度
stack -n 3 com.example.MyClass myMethod
# 根据条件表达式进行过滤
stack com.example.MyClass myMethod 'params[0] > 0'
tt - 时间隧道
tt (Time Tunnel) 命令用于记录方法的调用,并支持回放:
# 记录方法调用
tt -t com.example.MyClass myMethod
# 查看记录的调用
tt -l
# 查看指定ID的调用详情
tt -i 1001
# 重放指定ID的调用
tt -i 1001 -p
脚本和高级功能
options - 全局配置
options命令用于设置Arthas的全局开关:
# 查看所有配置项
options
# 修改单个配置
options unsafe true
profiler - 性能分析
profiler命令支持生成应用热点火焰图:
# 启动分析
profiler start
# 获取分析结果
profiler stop --file /tmp/result.html
# 支持不同的采样方式
profiler start --event cpu
profiler start --event alloc
ognl - 执行OGNL表达式
ognl命令用于执行OGNL表达式,可以动态获取和修改运行中的应用对象:
# 获取静态字段
ognl '@com.example.MyClass@FIELD'
# 调用静态方法
ognl '@com.example.MyClass@staticMethod()'
# 获取SpringContext中的bean
ognl '#springContext=@com.example.Config@applicationContext,#springContext.getBean("beanName")'
实战案例
案例1:定位CPU使用率高的问题
问题描述:线上应用CPU使用率突然飙高,需要快速定位原因。
解决步骤:
- 使用
dashboard
命令查看系统整体情况:
dashboard
- 使用
thread
命令找出CPU使用率高的线程:
thread -n 3
- 查看对应线程的调用栈,找到可能的热点方法:
thread 线程ID
- 使用
trace
命令追踪热点方法的执行情况:
trace 热点类 热点方法
- 根据结果分析耗时较长的方法,确定CPU高的根本原因。
案例2:定位内存泄漏问题
问题描述:应用运行一段时间后内存持续增长,怀疑存在内存泄漏。
解决步骤:
- 使用
dashboard
命令查看内存使用趋势:
dashboard
- 使用
heapdump
命令生成堆转储文件:
heapdump /tmp/leak.hprof
使用MAT等工具分析堆转储文件,找出可疑对象。
使用
sc
和sm
命令查看可疑类和方法:
sc -d 可疑类
sm -d 可疑类 可疑方法
- 使用
watch
命令监控对象创建情况:
watch 可疑类 可疑方法 '{params, returnObj}' -x 3
- 根据监控结果分析内存泄漏的根本原因。
案例3:热修复线上Bug
问题描述:线上应用出现bug,需要在不重启应用的情况下紧急修复。
解决步骤:
- 使用
jad
命令反编译有bug的类:
jad --source-only com.example.BugClass > BugClass.java
修改Java文件,修复bug。
使用
mc
命令编译修改后的Java文件:
mc -d /tmp/output /path/to/BugClass.java
- 使用
redefine
命令热更新类:
redefine /tmp/output/com/example/BugClass.class
- 使用
watch
或trace
命令验证修复是否生效:
watch com.example.BugClass bugMethod '{params, returnObj}' -x 3
案例4:排查接口超时问题
问题描述:某个接口偶发性超时,需要定位原因。
解决步骤:
- 使用
trace
命令追踪接口方法的执行过程:
trace com.example.Controller requestMethod '#cost > 1000'
分析输出结果,找出耗时较长的方法。
使用
stack
命令查看耗时方法的调用栈:
stack 耗时类 耗时方法
- 使用
watch
命令监控关键方法的入参和返回值:
watch 耗时类 耗时方法 '{params, returnObj}' -x 3
- 根据监控结果分析超时原因,如数据库查询效率低、外部服务调用慢等。
案例5:线程死锁分析
问题描述:应用出现卡顿,怀疑存在线程死锁。
解决步骤:
- 使用
thread -b
命令检查是否存在死锁:
thread -b
- 如果存在死锁,查看死锁线程的详细信息:
thread 死锁线程ID
分析死锁线程的堆栈信息,找出死锁的资源和代码位置。
使用
jad
命令反编译相关类,查看锁的获取逻辑:
jad 死锁相关类
- 根据分析结果,制定死锁解决方案。
最佳实践与注意事项
性能影响
虽然Arthas是一个强大的工具,但使用不当可能会对线上应用造成性能影响:
避免长时间运行:如
trace
、monitor
等命令会增加方法调用的开销,应避免长时间运行。合理设置条件表达式:使用条件表达式过滤掉不需要的调用,减少数据收集量。
使用采样:对于高频调用的方法,可以使用采样参数减少采集频率。
避免对频繁调用的方法使用重量级命令:如
watch
命令观察每次参数和返回值会产生大量数据。
安全建议
在生产环境使用Arthas需要注意以下安全事项:
访问控制:确保Arthas服务的端口不对外网开放,必要时设置认证。
权限管理:使用Arthas的用户应具有相应的权限,避免非授权访问。
避免修改业务数据:使用
ognl
等命令时,避免修改关键业务数据或状态。谨慎使用热更新:
redefine
命令虽然强大,但可能引入新的问题,应在充分测试后使用。
使用技巧
- 使用管道和grep过滤结果:
thread | grep 'waiting for monitor'
- 保存命令输出到文件:
jad --source-only com.example.MyClass > MyClass.java
- 使用批处理模式:
telnet localhost 3658 < commands.txt
使用Web Console:Arthas提供了Web界面,更直观地查看结果。
构建命令别名:对于常用的复杂命令,可以创建别名简化使用。
总结
Arthas作为一款功能强大的Java应用诊断工具,为开发人员提供了一种非侵入式的方式来分析和解决线上问题。通过本文的介绍和实战案例,相信大家已经对Arthas的核心功能和使用方法有了深入的了解。
在实际工作中,掌握Arthas可以帮助我们:
- 快速定位线上问题,减少平均故障修复时间(MTTR)
- 在不重启应用的情况下修复紧急Bug
- 深入分析应用性能瓶颈,持续优化系统性能
- 增强对JVM和应用运行机制的理解
最后,需要强调的是,虽然Arthas非常强大,但它是一把"双刃剑",在生产环境中使用时应当谨慎,遵循"先观察、后修改"的原则,确保操作的安全性。