线上 CPU 飙高是一个常见的性能问题,可能会导致系统响应变慢甚至服务不可用。以下是详细的排查思路和解决方案:
1. 确认 CPU 飙高
- 使用
top
命令:- 运行
top
命令,查看当前系统的 CPU 使用情况。 - 按
P
键按 CPU 使用率排序,找到占用 CPU 最高的进程。 - 记录下占用 CPU 最高的进程 ID(PID)。
- 运行
2. 定位问题线程
- 使用
top -H -p <pid>
:- 运行
top -H -p <pid>
,查看指定进程的线程 CPU 使用情况。 - 按
P
键按 CPU 使用率排序,找到占用 CPU 最高的线程 ID(TID)。 - 将线程 ID 转换为 16 进制(用于后续分析):
printf "%x\n" <tid>
- 运行
3. 分析线程堆栈
- 使用
jstack
:- 运行
jstack <pid>
获取 Java 进程的线程堆栈信息。 - 在堆栈信息中查找上一步得到的 16 进制线程 ID,定位到具体的线程。
- 分析线程的堆栈信息,查看线程正在执行的任务。
- 运行
- 使用
jcmd
:- 运行
jcmd <pid> Thread.print
获取线程堆栈信息。
- 运行
- 使用 Arthas:
- 如果安装了 Arthas,可以使用
thread
命令快速定位高 CPU 线程:thread -n 3 # 查看 CPU 使用率最高的 3 个线程 thread <tid> # 查看指定线程的堆栈信息
- 如果安装了 Arthas,可以使用
4. 分析代码
- 检查高 CPU 线程的堆栈:
- 如果线程正在执行某个方法,检查该方法是否有性能问题(如死循环、复杂计算等)。
- 如果线程处于等待状态(如
WAITING
或TIMED_WAITING
),可能是锁竞争或资源等待问题。
- 常见原因:
- 死循环:检查是否有未正确退出的循环。
- 频繁 GC:检查是否有频繁的 Full GC 导致 CPU 飙高。
- 锁竞争:检查是否有过多的线程竞争同一把锁。
- 复杂计算:检查是否有耗时的计算任务。
5. 使用 Profiling 工具
- Async Profiler:
- 使用 Async Profiler 对 Java 进程进行采样分析,生成火焰图。
- 示例:
./profiler.sh -d 60 -f /tmp/flamegraph.html <pid>
- 打开生成的火焰图,查看 CPU 消耗最多的方法。
- JProfiler:
- 使用 JProfiler 进行实时性能分析,定位 CPU 热点。
- Arthas Profiler:
- 使用 Arthas 的
profiler
命令进行采样分析:profiler start # 开始采样 profiler stop # 停止采样并生成火焰图
- 使用 Arthas 的
6. 检查系统资源
- 使用
vmstat
:- 运行
vmstat 1
,查看系统的 CPU、内存、IO 等资源使用情况。 - 如果
us
(用户态 CPU)较高,说明是应用程序占用 CPU;如果sy
(内核态 CPU)较高,可能是系统调用或 IO 问题。
- 运行
- 使用
sar
:- 运行
sar -u 1
,查看 CPU 使用率的历史趋势。
- 运行
7. 检查 GC 情况
- 使用
jstat
:- 运行
jstat -gc <pid> 1000
,查看 GC 情况。 - 如果 Full GC 频繁,可能是内存不足或内存泄漏导致 CPU 飙高。
- 运行
- 检查 GC 日志:
- 如果启用了 GC 日志,检查是否有频繁的 Full GC 或长时间的 GC 停顿。
8. 检查外部依赖
- 数据库查询:
- 检查是否有慢查询或全表扫描导致数据库负载过高。
- 远程调用:
- 检查是否有频繁的远程调用(如 HTTP、RPC)导致 CPU 飙高。
9. 解决方案
- 优化代码:
- 修复死循环、减少锁竞争、优化复杂计算。
- 调整 JVM 参数:
- 调整堆内存大小、选择合适的 GC 算法。
- 扩容:
- 如果单机性能不足,可以考虑扩容或分布式部署。
- 限流降级:
- 对于突发流量,可以使用限流或降级策略保护系统。
10. 总结
- 使用
top
找到高 CPU 进程。 - 使用
top -H -p <pid>
找到高 CPU 线程。 - 使用
jstack
或 Arthas 分析线程堆栈。 - 使用 Profiling 工具(如 Async Profiler)生成火焰图,定位热点代码。
- 结合代码和系统资源使用情况,找到根本原因并解决。
通过以上步骤,可以快速定位和解决线上 CPU 飙高的问题。
THE END
暂无评论内容