服务器CPU高、内存低排查
服务器CPU高、内存低排查-方案详解(通俗版)
先明确核心前提:CPU高、内存低,和“内存高、CPU低”是反过来的问题——不是资源不够用,而是服务器在“拼命干活”(比如计算量大、循环异常、IO等待、锁竞争等)。
下面全程沿用“现象→原因→判断方法→解决方法(前因后果)”的逻辑,不绕弯、不堆砌命令,每一步都讲清“为什么这么做”。
一、先定性:CPU到底在“忙什么”(第一步必做)
👉 核心判断手段:top命令(关键中的关键)
直接在服务器输入 top 命令,重点看 %Cpu(s) 这一行,4个指标直接决定排查方向,不用记复杂命令,盯紧这一行就够了:
us(用户态):程序自身运行消耗的CPU(比如Java、Python程序计算);sy(内核态):系统内核处理任务消耗的CPU(比如网络调用、文件操作);wa(IO等待):CPU没事干,一直在等磁盘/网络IO完成(看似CPU高,实则在“摸鱼”);id(空闲):CPU空闲率,越低说明CPU越忙(id<20%说明CPU已过载)。
✅ 为什么先看这一步?
很多人排查CPU高,一上来就找进程,反而绕弯路。先看这4个指标,能直接锁定“CPU忙的类型”,比如us高就是程序问题,sy高就是系统问题,wa高就是IO问题,节省80%的排查时间。
二、按“CPU忙的类型”分类排查(实战版)
场景1:user CPU高(us > 70%,最常见)
👉 现象(一眼识别)
top命令中,
us数值持续高于70%,id空闲率低于30%;能看到某个具体进程(比如java、python、nginx)的CPU占用率接近100%;
内存占用很低,无明显卡顿,但服务器响应变慢(CPU被占满,没时间处理新请求)。
📌 原因(为什么会这样?)
计算密集型任务:比如程序在执行大量循环、复杂算法(如大数据计算、视频转码);
程序漏洞:最常见的是死循环(程序一直重复执行某段代码,不退出,持续消耗CPU);
算法低效:代码写得不好(比如双重循环嵌套过多),导致CPU无效消耗。
✅ 解决方法(前因后果,一步一步来)
- 第一步:找“元凶进程”(为什么这么做?先锁定哪个程序在搞事)
命令:
top输入后,按 Shift + P(大写P),进程会按CPU占用率从高到低排序;重点记:CPU最高的进程ID(
),后续所有操作都围绕这个pid展开。
- 第二步:找“元凶线程”(为什么这么做?一个进程可能有多个线程,要精准到具体线程)
命令:
top -H -p <pid>(替换成第一步找到的进程ID);作用:查看该进程下所有线程的CPU占用,找到CPU最高的线程(记线程ID
)。
- 第三步:定位具体代码(为什么这么做?找到线程对应的代码,才能根治问题)
按程序语言分类,命令直接套用,不用记复杂原理:
Java程序(SpringBoot、Tomcat等):
jstack <pid>→ 导出线程栈,找到对应线程()的代码行,排查死循环/低效代码; Python程序(Django、Flask等):
py-spy top→ 实时查看Python程序的CPU消耗情况,定位耗CPU的代码;通用方法(所有语言):
perf top→ 查看系统级CPU消耗,快速定位耗CPU的函数/进程。
- 最终处理(为什么这么做?治标+治本,避免复发)
治本:优化算法(简化复杂循环)、修复死循环漏洞(比如增加退出条件);
治标:限制进程线程数(避免单个程序占满CPU)、降低并发量(减少CPU计算压力);
兜底:如果是正常计算任务(比如大数据分析),直接扩容CPU(增加核心数)。
场景2:system CPU高(sy > 30%,容易被忽略)
👉 现象(一眼识别)
top命令中,
sy数值持续高于30%,us数值不高;看不到单个高CPU进程,但整体CPU使用率很高;
服务器响应卡顿,网络请求延迟高(内核一直在处理系统调用,没时间处理业务请求)。
📌 原因(为什么会这样?)
频繁系统调用:程序频繁调用内核接口(比如频繁读写文件、频繁创建/销毁进程);
网络包过多:服务器接收/发送大量网络包(比如被攻击、请求量暴增),内核处理不过来;
锁竞争:多线程/多进程频繁竞争锁(比如Java的synchronized锁),内核频繁切换线程;
上下文切换频繁:CPU在多个线程/进程之间频繁切换,浪费大量CPU资源。
✅ 解决方法(前因后果,一步一步来)
- 第一步:查看上下文切换(为什么这么做?判断是否是切换频繁导致的sy高)
命令:
vmstat 1(每1秒输出一次系统状态);重点看:
cs(context switch,上下文切换次数),正常情况下每秒几千次,超过1万次就是切换过于频繁。
- 第二步:查看网络情况(为什么这么做?排除网络包过多导致的内核繁忙)
命令:
sar -n DEV 1(每1秒输出一次网卡状态);重点看:网卡的接收(rxpck/s)、发送(txpck/s)包数,是否远超正常范围(比如每秒几万包,可能是被攻击)。
- 第三步:优化方向(为什么这么做?针对性解决内核繁忙的根源)
减少锁竞争:优化代码,减少多线程锁竞争(比如用无锁机制、分段锁);
调整线程模型:比如Java程序用IO多路复用(NIO),减少系统调用次数;
优化网络:限制连接数、调整网络队列大小,避免网卡打满;
内核调优:调整内核参数(比如减少上下文切换开销),需谨慎操作(建议备份配置)。
场景3:IO wait高(wa > 30%,看似CPU高,实则在“等”)
👉 现象(一眼识别)
top命令中,
wa数值持续高于30%,us、sy数值不高;CPU使用率看似很高,但服务器特别卡顿(CPU没事干,一直在等磁盘/网络IO);
内存占用低,磁盘读写指示灯常亮(或网络延迟高)。
📌 原因(为什么会这样?)
磁盘太慢:用的是机械硬盘(HDD),频繁读写大文件,CPU一直等磁盘响应;
IO阻塞:程序频繁做同步IO操作(比如每次写文件都等待写入完成),不做缓存;
网络存储问题:使用NFS、SMB等网络存储,网络延迟高,CPU等待存储响应。
✅ 解决方法(前因后果,一步一步来)
- 第一步:查看磁盘IO状态(为什么这么做?锁定是否是磁盘导致的wa高)
命令:
iostat -x 1(每1秒输出一次磁盘IO详情);重点看两个指标:
await:磁盘IO平均等待时间(单位ms),超过50ms说明磁盘IO很慢;util:磁盘使用率,接近100%说明磁盘被打满(一直在读写,没时间响应其他请求)。
- 第二步:处理方式(为什么这么做?针对性解决IO等待问题,让CPU“有事干”)
硬件优化:把机械硬盘(HDD)换成固态硬盘(SSD),IO速度提升10倍以上;
软件优化:减少同步IO,增加缓存(比如用Redis缓存频繁读取的文件/数据),批量处理IO操作(比如批量写入文件,而非单次写入);
网络存储优化:检查网络延迟,更换更快的网络存储,或把常用数据缓存到本地磁盘。
场景4:CPU被打满,但无明显高CPU进程
👉 现象(一眼识别)
top命令中,CPU使用率接近100%,但按Shift+P排序,没有单个进程CPU占比超过20%;
服务器卡顿,响应缓慢,内存占用低;
可能伴随
si(软中断)数值偏高(top命令中能看到)。
📌 原因(为什么会这样?)
内核线程:系统内核自身的线程(比如磁盘IO线程、网络中断线程)消耗CPU;
中断风暴:硬件中断(比如网卡、磁盘)或软中断过多,CPU一直处理中断,无法处理业务请求(最常见的是网卡中断风暴)。
✅ 解决方法(前因后果,一步一步来)
- 第一步:查看中断情况(为什么这么做?判断是否是中断导致的CPU高)
查看硬件中断:
cat /proc/interrupts→ 查看各硬件(网卡、磁盘)的中断次数,次数异常多的就是问题所在;查看软中断:
top命令中,重点看si(softirq)数值,超过10%就是软中断过高。
- 第二步:针对性解决(为什么这么做?减少中断对CPU的消耗)
网卡中断风暴(最常见):调整网卡中断配置,开启多队列(RSS),将网卡中断分散到多个CPU核心处理;
开启RPS/XPS:内核参数优化,将网络包分发到多个CPU处理,减少单个CPU的中断压力;
检查硬件:如果是磁盘中断过高,检查磁盘是否故障,或调整磁盘IO调度策略。
场景5:容器 / Kubernetes环境(生产最常见)
👉 现象(一眼识别)
宿主机CPU高、内存低,top看不到明显高CPU进程;
容器环境中,某个Pod/容器的CPU占用率接近100%;
其他容器响应变慢(被高CPU容器抢占资源)。
📌 原因(为什么会这样?)
容器未限制CPU:Docker/K8s容器默认不限制CPU使用,某个容器出现CPU高(比如死循环),会占满宿主机所有CPU;
容器并发过高:容器内程序并发量太大,导致CPU被占满,而内存占用很低(未达到内存限制)。
✅ 解决方法(前因后果,一步一步来)
- 第一步:找到异常容器(为什么这么做?锁定哪个容器在消耗CPU)
Docker环境:
docker stats→ 实时查看所有容器的CPU、内存占用,找到高CPU容器;K8s环境:
kubectl top pod→ 查看所有Pod的CPU占用,找到高CPU Pod。
- 第二步:限制容器CPU(为什么这么做?隔离资源,避免单个容器拖垮宿主机)
K8s配置示例(直接复制套用):
1 | resources: |
Docker配置:启动容器时加
--cpus 1参数,限制容器最大使用1个CPU核心;作用:即使容器内程序出现CPU高问题,也不会超过限制,不影响宿主机和其他容器。
- 第三步:优化容器内程序(为什么这么做?根治问题,避免容器反复CPU高)
进入容器,按前面“场景1~4”的方法,排查容器内程序的CPU高原因(比如死循环、算法低效);
调整容器并发量,避免容器内程序过度消耗CPU。
三、快速判断套路(实战版,直接套用)
不用记复杂命令,按这个流程来,1分钟锁定排查方向,适合新手:
| 指标(top命令) | 结论(CPU在忙什么) | 核心处理方向 |
|---|---|---|
| us 高(>70%) | 程序自身计算消耗CPU | 找进程→找线程→优化代码/限流 |
| sy 高(>30%) | 系统内核消耗CPU | 查上下文切换→优化网络/锁竞争 |
| wa 高(>30%) | CPU在等IO(磁盘/网络) | 查磁盘IO→换SSD/加缓存 |
| si 高(>10%) | 软中断过多 | 查网卡→调整中断配置 |
| 无明显高进程 | 内核线程/中断 | 查/proc/interrupts→硬件优化 |
| 容器环境 | 容器未限CPU | 查容器→限制CPU+优化容器内程序 |
四、最常见真实原因(经验总结,避坑)
实际工作中,CPU高、内存低,大概率是这5种情况,优先排查:
Java程序CPU 100%:死循环、GC异常(频繁Full GC)、算法低效;
Nginx/网关被打爆:请求量暴增,未做限流,CPU被请求处理占满;
数据库慢查询:大量慢SQL导致数据库CPU飙升,进而影响整个服务器;
容器未限CPU:某个容器出现问题,占满宿主机CPU;
日志疯狂打印:程序异常,频繁打印大量日志,导致CPU和磁盘IO双重消耗(容易被忽略)。
五、最后一句实用忠告(重点)
CPU高 ≠ 服务器资源不够,而是“有人在拼命干活”——
你要做的不是急着加CPU、加机器,而是:
找到“谁在干活”(哪个进程/线程/容器);
看他“为什么这么忙”(死循环?计算多?IO等?);
要么让他“少干活”(优化代码、限流),要么让他“高效干活”(优化算法、加缓存)。
补充:快速定位小技巧
如果不知道自己的服务器是哪种情况,执行以下3个命令,把输出发给我,就能直接判断问题类型+给具体解决方案:
1 | top -b -n 1 # 查看CPU整体状态(一次性输出,不实时刷新) |
