你好,我是风一样的树懒,一个工作十多年的后端开发,曾就职京东、阿里等多家互联网头部企业。
文章可能会比较长,主要解析的非常详解,或涉及一些底层知识,供面试高阶难度用。可以根据自己实际理解情况合理取舍阅读
graph TD
A[问题现象] --> B{选择切入点}
B -->|CPU高| C[线程/方法级分析]
B -->|响应慢| D[调用链路追踪]
B -->|内存泄漏| E[堆内存监控]
C --> F[定位热点代码]
D --> F
E --> F
F --> G[优化验证]
# 实时监控面板(每秒刷新)
dashboard -i 1000 -n 5
关键指标:
THREAD:高CPU线程ID
MEM:堆内存/非堆内存占用
RUNNING:阻塞线程数
# 显示最忙线程Top3
thread -n 3
# 查看具体线程堆栈
thread <线程ID>
典型案例:
"catalina-exec-1" Id=25 RUNNABLE
at com.example.OrderService.calculateTax(OrderService.java:87) # 高CPU方法
# 监控方法执行耗时(5秒采样)
profiler start --event cpu --duration 5
profiler stop --format html > /tmp/cpu_profile.html
火焰图分析:
平顶山:单一方法高消耗
宽基座:基础方法高频调用
# 监控方法入参/返回值
watch com.example.OrderService calculateTax '{params, returnObj}' -n 5 -x 3
输出示例:
method=com.example.OrderService.calculateTax location=AtExit
params[0]=Order[id=123,amount=1000.0]
returnObj=150.0
# 统计方法执行耗时(阈值500ms)
trace com.example.*Service * '#cost>500' -n 5
输出解读:
`---ts=2023-08-20 15:32:45;thread_name=catalina-exec-3;id=2e;is_daemon=true;priority=5;TCCL=org.springframework.boot.loader.LaunchedURLClassLoader@4b85612c
`---[521.743075ms] com.example.UserService:getUserDetail()
+---[0.12% 0.65ms] com.example.dao.UserDAO:selectById() #1
+---[98.73% 515.2ms] java.net.SocketInputStream:socketRead0() #2 <--- 网络阻塞
`---[1.15% 6.0ms] com.example.util:formatUser() #3
# 跟踪Spring MVC接口全链路
trace org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter invokeHandlerMethod '#cost>1000'
# 监控JDBC连接池
watch org.apache.tomcat.jdbc.pool.ConnectionPool * '{params,returnObj,throwExp}' -x 3
# 生成HeapDump(需JDK8+)
heapdump /tmp/heap.hprof
# 对象直方图统计
heap --live | grep com.example
# 查找泄漏对象
vmtool --action getInstances --className com.example.CacheManager --express 'instances.length'
# 追踪对象GC Root
options unsafe true
ognl '@com.taobao.arthas.core.util.ObjectUtils@getGcRoot(instances[0])'
# 跟踪ReferenceQueue
watch java.lang.ref.ReferenceQueue poll 'returnObj != null' -x 3
# 热更新方法(需编译.class)
redefine /tmp/UserService.class
# 监控锁竞争
monitor -c 5 java.util.concurrent.locks.ReentrantLock getQueueLength
# 临时修改日志级别
logger --name ROOT --level debug
## 问题现象
- 现象:API响应时间从50ms突增至2s
- 时段:2023-08-20 14:00 ~ 15:00
## Arthas诊断过程
1. `dashboard`发现线程池满
2. `thread -n 3`定位到DB连接线程阻塞
3. `trace`追踪到MyBatis批量插入操作
4. `watch`监控到SQL参数包含10万条记录
## 根因分析
- 批量插入未分页导致数据库锁表
## 优化方案
- 增加批量操作分页限制(每批500条)
- 添加SQL执行时间监控
# ~/.arthasrc
alias cpu_top=thread -n 3
alias trace_slow=trace *Service '*' '#cost>500'
2.安全防护:
生产环境限制options unsafe使用
通过shutdown命令及时断开连接
# 诊断自动化脚本示例
echo "thread -n 3" | java -jar arthas-client.jar 127.0.0.1 3658
通过系统化的Arthas诊断框架,可实现 5分钟定位常见问题,30分钟攻克复杂故障。
今天的内容就分享到这儿,喜欢的朋友可以关注,点赞。有什么不足的地方欢迎留言指出,您的关注是我前进的动力!