场景题:线上 CPU 飙高如何排查?

线上 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> # 查看指定线程的堆栈信息

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  # 停止采样并生成火焰图

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. 总结

  1. 使用 top 找到高 CPU 进程。
  2. 使用 top -H -p <pid> 找到高 CPU 线程。
  3. 使用 jstack 或 Arthas 分析线程堆栈。
  4. 使用 Profiling 工具(如 Async Profiler)生成火焰图,定位热点代码。
  5. 结合代码和系统资源使用情况,找到根本原因并解决。

通过以上步骤,可以快速定位和解决线上 CPU 飙高的问题。

THE END
点赞6 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容