【运维排查】服务器CPU飙升100%?别慌,教你3步精准定位“罪魁祸首”

简介: 当服务器CPU飙高时,别急着重启!本文教你四步精准排查:用`top`定位高占用进程,`top -Hp`找出耗CPU线程,`printf`转十六进制,再通过`jstack`结合线程ID定位到具体代码行。快速锁定死循环、频繁GC或复杂计算等问题根源,成为团队中的故障排查高手。

前言

“滴滴滴...” 手机突然收到阿里云云监控的报警短信:“您的ECS实例 CPU使用率已超过 90%”

此时,你的服务可能响应缓慢,甚至直接502。面对这种情况,很多新手的反应是直接重启服务器。虽然重启能暂时解决问题,但找不到根因,问题迟早会卷土重来。

今天,我将分享一套**“教科书级”**的CPU飙高排查思路,只需几行命令,就能精准定位到是哪一行代码搞崩了服务器。

第一步:全局定位——找到耗资源的进程 (PID)

首先,我们需要知道是哪个程序(进程)占用了CPU。

  1. 在终端输入 top 命令。
  2. 进入界面后,按下大写 P 键,系统会按照 CPU使用率 对进程进行降序排列。

Bash

top - 14:28:32 up 10 days,  3:14,  2 users,  load average: 2.10, 1.05, 0.56
Tasks: 102 total,   1 running, 101 sleeping,   0 stopped,   0 zombie
%Cpu(s): 98.5 us,  1.2 sy,  0.0 ni,  0.3 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
PID    USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
12345  root      20   0   2.5g   500m   10m S  99.0 20.5   10:15.20 java

分析:如上图所示,PID为 12345java 进程CPU占用率高达 99.0%,它就是我们要找的目标。

第二步:深度挖掘——找到耗资源的线程 (TID)

一个进程往往包含多个线程,我们需要知道具体是哪个线程在“作恶”。

使用命令 top -Hp <PID>,其中 <PID> 替换为上一步找到的进程ID。

Bash

# 查看进程 12345 下的所有线程
top -Hp 12345

进入界面后,同样按下 P 键排序:

Bash

PID    USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
12368  root      20   0   2.5g   500m   10m R 95.5  0.0   05:10.20 java
12369  root      20   0   2.5g   500m   10m S  1.2  0.0   00:05.10 java

分析:我们发现 PID(在线程视图中其实是 Thread ID)为 12368 的线程占用了绝大部分CPU。

第三步:进制转换——准备定位代码

Linux中的线程ID是十进制的(如 12368),而在Java堆栈日志中,线程ID通常是以十六进制(Hex)显示的。我们需要进行一次转换。

可以使用 printf 命令:

Bash

# 将 12368 转换为十六进制
printf "%x\n" 12368

输出:3050

记下这个十六进制数字:0x3050

第四步:真相大白——定位具体代码行数

现在我们有了进程ID(12345)和十六进制的线程ID(0x3050),就可以使用 Java 自带的 jstack 工具来导出堆栈信息,并抓取“案发现场”。

Bash

# 打印堆栈信息,并使用 grep 查找 0x3050,显示匹配行的后 20 行
jstack 12345 | grep "0x3050" -A 20

输出示例:

"Thread-5" #25 prio=5 os_prio=0 tid=0x00007f8... nid=0x3050 runnable [0x00007f8...]
   java.lang.Thread.State: RUNNABLE
    at com.example.demo.controller.TestController.loop(TestController.java:28)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    ...

终极分析:仔细看输出日志的 at com.example.demo.controller.TestController.loop(TestController.java:28)。 真相只有一个:TestController.java 文件的第 28 行

通常这里可能存在:

  1. 死循环: 代码逻辑错误导致 while(true) 且没有退出条件。
  2. 频繁GC: 如果看到是 GC task thread 占用高,说明内存泄露导致了频繁的 Full GC。
  3. 复杂计算: 大量的数学运算或加密解密操作。

总结

以后遇到 CPU 100% 的情况,不要慌,按照这个套路走:

  1. top → 找 进程ID (PID)
  2. top -Hp PID → 找 线程ID (TID)
  3. printf "%x\n" TID → 转 十六进制 (Hex)
  4. jstack PID | grep Hex -A 20 → 找 问题代码

掌握这个排查链路,你就是团队里那个能“秒级定位问题”的专家!

相关文章
IDEA第一次上传项目到gitlab
IDEA第一次上传项目到gitlab步骤
1985 1
|
存储 Java 网络安全
SpringCloud GateWay配置(TLS 和 SSL、Http超时配置)—官方原版
SpringCloud GateWay配置(TLS 和 SSL、Http超时配置)—官方原版
2378 0
|
4月前
|
人工智能 Java Nacos
基于 Spring AI Alibaba + Nacos 的分布式 Multi-Agent 构建指南
本文将针对 Spring AI Alibaba + Nacos 的分布式多智能体构建方案展开介绍,同时结合 Demo 说明快速开发方法与实际效果。
3636 78
|
定位技术
百度地图开发:map.setViewport让标注显示在最佳视野内
百度地图开发:map.setViewport让标注显示在最佳视野内
716 0
|
运维 监控 安全
在Linux中,如何进行故障排查?
在Linux中,如何进行故障排查?
|
安全 Java API
时间日期API(Date,SimpleDateFormat,Calendar)+java8新增日期API (LocalTime,LocalDate,LocalDateTime)
这篇文章介绍了Java中处理日期和时间的API,包括旧的日期API(Date、SimpleDateFormat、Calendar)和Java 8引入的新日期API(LocalTime、LocalDate、LocalDateTime)。文章详细解释了这些类/接口的方法和用途,并通过代码示例展示了如何使用它们。此外,还讨论了新旧API的区别,新API的不可变性和线程安全性,以及它们提供的操作日期时间的灵活性和简洁性。
|
canal 消息中间件 缓存
面试题:如何解决缓存和数据库的一致性问题?
面试题:如何解决缓存和数据库的一致性问题?
513 1
|
安全 Java API
【三方服务集成】最新版 | 阿里云短信服务SMS使用教程(包含支持单双参数模板的工具类,拿来即用!)
阿里云短信服务提供API/SDK和控制台调用方式,支持验证码、通知、推广等短信类型。需先注册阿里云账号并实名认证,然后在短信服务控制台申请资质、签名和模板,并创建AccessKey。最后通过Maven引入依赖,使用工具类发送短信验证码。
6644 3
【三方服务集成】最新版 | 阿里云短信服务SMS使用教程(包含支持单双参数模板的工具类,拿来即用!)
|
安全 Java API
实现跨域请求:Spring Boot后端的解决方案
本文介绍了在Spring Boot中处理跨域请求的三种方法:使用`@CrossOrigin`注解、全局配置以及自定义过滤器。每种方法都适用于不同的场景和需求,帮助开发者灵活地解决跨域问题,确保前后端交互顺畅与安全。
1983 0