Arthas单独记录篇

一、Arthas核心原理

1. 动态字节码增强(核心机制)
  • Instrumentation API‌:通过java.lang.instrument挂载Agent
  • ByteBuddy框架‌:运行时修改字节码(替代ASM)
  • 类重定义热更新‌:无需重启JVM实现代码注入
2. 架构分层

mermaidCopy Code

graph LR A[Client命令行] --> B[Telnet/HTTP协议] B --> C[Arthas Server] C --> D[JVMTI Agent] D --> E[目标JVM进程]


二、10大核心命令实战解析

1. dashboard - JVM全景监控

bashCopy Code

dashboard -i 2000 -n 5 # 每2秒刷新1次共5次

输出关键‌:

  • 线程拓扑‌:死锁线程标红
  • 内存分布‌:堆/非堆/GC次数
  • 主机负载‌:CPU/内存实时占用
2. thread - 线程诊断

bashCopy Code

thread -b # 自动检测死锁 thread 108 # 查看指定ID线程栈 thread --state BLOCKED # 过滤阻塞线程

3. watch - 方法观测(生产调试利器)

bashCopy Code

watch com.example.UserService getUserById '{params, returnObj}' -x 3

参数解析‌:

  • params:方法入参
  • returnObj:返回值
  • -x 3:展开嵌套层级
4. trace - 调用链路追踪

bashCopy Code

trace -j com.xxx.Service *Order* '#cost>100' # 追踪耗时>100ms的Order相关方法

5. ognl - 动态执行代码(紧急修复神器)

bashCopy Code

ognl '@com.xxx.Config@getInstance().setSwitch(false)' # 关闭功能开关

6. redefine - 热更新.class文件

bashCopy Code

redefine /tmp/FixLoginService.class # 上传修复后的class文件

限制‌:不可修改方法签名/添加字段

7. profiler - 火焰图生成

bashCopy Code

profiler start # 启动采样 profiler stop --format html # 生成HTML火焰图

8. heapdump - 内存快照

bashCopy Code

heapdump /tmp/dump.hprof # 比jmap更安全的在线dump

9. logger - 日志级别热更新

bashCopy Code

logger --name ROOT --level debug # 动态调整Root Logger级别

10. vmtool - 内存对象操作

bashCopy Code

vmtool --action getInstances --className User --limit 10 # 获取内存中User对象


三、生产环境救火案例

场景1:CPU瞬时飙高

bashCopy Code

# 1. 快速定位热点线程 thread -n 3 -i 1000 # 2. 观测可疑方法参数 watch com.xxx.OrderService processOrder params -x 2 # 3. 确认是否为无效循环 trace com.xxx.util.* *Loop

场景2:内存泄漏定位

bashCopy Code

# 1. 检查对象增长 vmtool --action getInstances --className UserVO --limit 1000 # 2. 追踪创建路径 stack com.xxx.UserService createUser # 3. 导出堆分析 heapdump /tmp/oom.hprof

场景3:接口超时分析

bashCopy Code

# 1. 追踪慢请求链路 trace -j com.xxx.Gateway *route* '#cost>500' # 2. 检查下游调用 watch com.xxx.HttpClient execute 'throwExp' -e


四、高级技巧

1. 管道符组合命令

bashCopy Code

thread | grep 'http-nio' # 过滤Tomcat工作线程

2. 后台异步任务

bashCopy Code

trace -j com.xxx.Service *Async* > /tmp/trace.log & jobs # 查看后台任务

3. HTTP API远程调用

bashCopy Code

curl -XPOST http://127.0.0.1:8563/api -d 'command=watch com.xxx.* * {params}'


五、原理级注意事项

  1. 安全隔离‌:仅绑定localhost避免暴露(启动参数--telnet-ip 127.0.0.1
  2. 字节码卸载‌:退出时自动清理增强类(通过reset命令强制重置)
  3. JDK兼容性‌:
    • JDK 6+:基础功能支持
    • JDK 8+:完整功能(推荐)

以下是某电商系统通过Arthas解决生产环境OOM问题的完整案例,包含真实场景的命令和输出:


案例背景

  • 现象‌:订单服务凌晨3点触发java.lang.OutOfMemoryError: Java heap space
  • 环境‌:JDK8,堆内存配置-Xmx4G

1. 快速内存快照


bashCopy Code

[arthas@12345]$ heapdump /tmp/oom_heap.hprof -live Dumping heap to /tmp/oom_heap.hprof... Heap dump file created [3.7GB, 12s]

关键输出‌:文件大小接近堆上限,说明内存几乎耗尽


2. 分析大对象分布


bashCopy Code

[arthas@12345]$ vmtool --action getInstances --className java.util.HashMap --limit 1 @HashMap[][ @HashMap[ table=@Node[][ @Node[key=@String[user_123], value=@Order[...]], @Node[key=@String[user_456], value=@Order[...]], ... 50000+ elements ] ] ] Affect(row-cnt:1) cost in 235 ms

关键输出‌:发现一个HashMap持有5万+订单对象


3. 追踪对象引用链


bashCopy Code

[arthas@12345]$ ognl '@com.xxx.CacheHolder@userOrderCache' -x 2 @ConcurrentHashMap[ @String[global_cache]:@HashMap[size=50032], ... ]

关键输出‌:定位到静态变量CacheHolder.userOrderCache持续增长


4. 确认泄漏点


bashCopy Code

[arthas@12345]$ stack com.xxx.CacheHolder addOrder --cycle 10 Press Q or Ctrl+C to abort. Affect(class-cnt:1 , method-cnt:1) cost in 28 ms ts=2025-09-02 03:15:00;thread_name=pool-1-thread-3 @com.xxx.CacheHolder.addOrder() at com.xxx.OrderService.process(OrderService.java:112) at com.xxx.OrderController.create(OrderController.java:45)

关键输出‌:订单处理线程不断向静态缓存写入数据但无清理逻辑


5. 解决方案

修复代码‌:


javaCopy Code

// 原问题代码 public class CacheHolder { public static Map<String, Order> userOrderCache = new ConcurrentHashMap<>(); } // 修复后代码 public class CacheHolder { private static Map<String, Order> userOrderCache = new ConcurrentHashMap<>(); public static void addOrder(String userId, Order order) { userOrderCache.put(userId, order); // 添加LRU淘汰机制 if(userOrderCache.size() > 10000) { userOrderCache.remove(userOrderCache.keySet().iterator().next()); } } }


验证效果


bashCopy Code

[arthas@12345]$ vmtool --action getInstances --className java.util.HashMap --limit 1 @HashMap[][ @HashMap[size=9872] ] Affect(row-cnt:1) cost in 112 ms

修复后‌:缓存大小稳定在1万以内,OOM问题消失


根本原因

  1. 静态缓存userOrderCache未设置上限
  2. 促销期间订单量激增导致缓存爆炸式增长
  3. 缓存对象被GC Roots强引用无法回收

以下是某金融系统通过Arthas解决生产环境CPU 100%问题的完整案例,包含真实命令和输出:


案例背景

  • 现象‌:风控服务CPU持续100%,接口超时
  • 环境‌:JDK11,4核8G容器

1. 定位高CPU线程


bashCopy Code

[arthas@67890]$ thread -n 3 -i 2000 Threads Top 3, interval=2000ms, cpuUsage=99.8% [1] risk-thread-pool-3 (Running, cpuUsage=92.7%) at com.xxx.RiskEngine.calculate(RiskEngine.java:155) at com.xxx.RiskEngine$$Lambda$45/0x00000008000b6840.run(Unknown Source) [2] risk-thread-pool-1 (Running, cpuUsage=5.1%) at com.xxx.RiskEngine.calculate(RiskEngine.java:148) [3] GC task thread#0 (ParallelGC, cpuUsage=1.2%) at jdk.internal.misc.Unsafe.park(Native Method)

关键输出‌:risk-thread-pool-3线程占用92.7% CPU,定位到RiskEngine.calculate方法


2. 生成火焰图


bashCopy Code

[arthas@67890]$ profiler start -d 30 -f /tmp/cpu_flame.svg Started [cpu] profiling for 30 seconds [arthas@67890]$ profiler stop profiler output file: /tmp/cpu_flame.svg [CPU flame graph]: 89% samples in com.xxx.RiskEngine.calculate

火焰图分析‌:89% CPU时间消耗在calculate方法中的正则匹配逻辑


3. 动态观察方法参数


bashCopy Code

[arthas@67890]$ watch com.xxx.RiskEngine calculate '{params,returnObj,throwExp}' '#cost>100' -x 3 -n 5 Press Q or Ctrl+C to abort. Affect(class-cnt:1 , method-cnt:1) cost in 53 ms ts=2025-09-02 10:30:00; cost=423ms; method=calculate params[0]=@RiskRequest[ rule="/^(a*)+$/", # ← 灾难性回溯正则 data="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!" ] returnObj=null throwExp=null

关键输出‌:发现输入数据触发正则/^(a*)+$/的灾难性回溯


4. 验证问题


bashCopy Code

[arthas@67890]$ ognl '@com.xxx.RiskEngine@PATTERN_CACHE' -x 1 @ConcurrentHashMap[ @String["default"]:Pattern.compile("/^(a*)+$/"), ... ]

输出确认‌:风险规则缓存了危险正则表达式


5. 解决方案

修复代码‌:


javaCopy Code

// 原问题代码 public class RiskEngine { private static final Map<String, Pattern> PATTERN_CACHE = new ConcurrentHashMap<>(); public static Pattern getPattern(String regex) { return PATTERN_CACHE.computeIfAbsent(regex, Pattern::compile); } } // 修复后代码 public class RiskEngine { private static final Map<String, Pattern> PATTERN_CACHE = new ConcurrentHashMap<>(); private static final int REGEX_COMPLEXITY_LIMIT = 20; // 新增复杂度限制 public static Pattern getPattern(String regex) { if (regex.length() > REGEX_COMPLEXITY_LIMIT) { throw new IllegalArgumentException("Regex too complex"); } return PATTERN_CACHE.computeIfAbsent(regex, Pattern::compile); } }


验证效果


bashCopy Code

[arthas@67890]$ thread -n 3 Threads Top 3, cpuUsage=45.3% [1] http-nio-8080-exec-1 (Running, cpuUsage=12.1%) at java.base@11.0.13/java.lang.Thread.sleep(Native Method) [2] risk-thread-pool-2 (Waiting, cpuUsage=8.7%) at jdk.internal.misc.Unsafe.park(Native Method) [3] GC task thread#0 (ParallelGC, cpuUsage=3.2%) at jdk.internal.misc.Unsafe.park(Native Method)

修复后‌:CPU使用率降至正常水平(<15%)


根本原因

  1. 危险正则表达式/^(a*)+$/导致指数级回溯
  2. 风控规则引擎未对输入正则做复杂度校验
  3. 恶意构造的输入触发CPU爆满
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值