排查思路:先定方向,再抓进程
遇到"服务器变慢",第一反应别急着重启。把排查拆成三步:
- 定方向:先看是 CPU、内存、磁盘 I/O 还是网络的问题——top 是总览仪表盘,
pidstat/iostat是精准探测器; - 抓进程:锁定具体是哪个进程在占用资源,看它是不是异常(死循环、内存泄漏、异常用户);
- 下结论:判断是资源不足、程序 bug 还是配置错误,再决定杀进程、改配置还是扩容。
后面所有命令都在 Ubuntu 24.04 上实测过。
top:系统总览仪表盘
top 是性能排查的第一站,一次刷新就能看到负载、CPU、内存和进程排行。
头部五行怎么读
top - 08:38:49 up 4 days, 13:56, 2 users, load average: 0.00, 0.05, 0.03
Tasks: 122 total, 1 running, 121 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.0 us, 4.5 sy, 0.0 ni, 95.5 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 1886.5 total, 689.7 free, 440.9 used, 949.2 buff/cache
MiB Swap: 3072.0 total, 2971.4 free, 100.6 used. 1445.5 avail Mem- load average:过去 1/5/15 分钟的任务队列平均长度(运行态 + 不可中断睡眠态进程的指数移动平均)。判断标准:负载 < CPU 核心数为正常,= 核心数为满载,> 2 倍核心数为严重过载。核心数用
nproc查看; - Tasks 行:total / running / sleeping / stopped / zombie——zombie 数不为 0 就要注意了(见下文僵尸进程章节);
- %Cpu(s):us(用户态)、sy(内核态)、id(空闲)、wa(I/O 等待)、st(被虚拟机偷走的时间)。us 高 → 应用层问题;sy 高(>20%)→ 系统调用频繁;wa 高 → CPU 在等磁盘,去查磁盘;
- Mem/Swap 行:真正要盯的是 avail Mem(available 列)——它是"现在能分出去的内存",比 free 列靠谱得多。free 少不代表内存不够,available 快没了且 Swap 开始涨才是真危机。
进程列表列解读
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 22896 9788 6420 S 0.0 0.5 0:25.85 systemd- VIRT / RES:虚拟内存 / 物理内存(RSS)。RES 才是实际占用的物理内存;
- S(STAT):R 运行、S 休眠、Z 僵死(zombie)、D 不可中断睡眠、T 停止。D 状态进程连 kill -9 都杀不掉;
- %CPU:单个逻辑核心的百分比。多核机器上多个满载线程总和超过 100%(比如 8 核满载显示 800%)是正常的;
- TIME+:进程累计消耗的 CPU 时间——如果一个进程 %CPU 不高但 TIME+ 很大,说明它长期偷偷干活。
交互快捷键与批处理模式
top # 进入交互界面
top -bn1 # 批处理模式,刷一次就退出(适合存快照、脚本用)
top -d 1 # 刷新间隔改为 1 秒,看趋势进去之后按键盘:P 按 CPU 排序、M 按内存排序、1 看每个核心、c 显示完整命令行、H 切到线程视图、i 隐藏空闲进程、q 退出。

ps:进程快照与排序定位
top 是动态的,ps 是静态快照,两者配合用。几个高频组合:
ps aux --sort=-%cpu | head -10 # CPU 占用 Top10
ps aux --sort=-%mem | head -10 # 内存占用 Top10
ps -ef --forest | head -20 # 带树状父子结构的完整列表
ps -eo pid,ppid,cmd,stat,%cpu,%mem | grep nginx # 精确过滤某个服务
pgrep -a python3 # 按名字找 PID,-a 显示命令行
pstree -p # 进程树实战判断:如果某个进程反复出现、父进程不断重启它(比如崩溃重启循环),ps -ef --forest 一眼就能看出父子关系链。
实战:CPU 打满怎么办
用 yes 命令模拟一个疯狂消耗 CPU 的进程(yes 会无限输出字符到 stdout,重定向到 /dev/null 让它纯烧 CPU):
yes > /dev/null & # 后台跑一个 CPU 杀手
Y=$!
sleep 3
top -bn1 | head -12 # 看谁在榜首
kill $Y # 确认后终止
截图中 yes 以 R(运行态)状态霸占榜首,%CPU 100.0——这就是"系统突然变慢"的典型现场。真实环境里要做的三步:top 按 P 排序 → 按 c 看完整命令行确认身份 → 确认无误再 kill(先 kill -15 优雅终止,无效再 kill -9)。
僵尸进程:kill 不掉的"尸体"
僵尸进程(STAT 列为 Z,命令名带 <defunct>)是已经结束、但父进程还没调用 wait() 回收的进程尸体。它不消耗 CPU 和内存,却不能被 kill -9 杀掉——你杀不掉一个已经死了的进程。
真正的处理对象是它的父进程。僵尸堆积会让 PID 号段耗尽、/proc 条目异常增多,间接拖慢系统。
# 找到僵尸进程和它的父进程(PPID)
ps -A -ostat,ppid,pid,cmd | grep -e '^[Zz]'
# 确认父进程是什么
ps -p <父PID> -o pid,stat,comm
# 终止父进程,僵尸由 init/systemd 自动收尸
kill -9 <父PID>
演示里用了一个不回收子进程的 Python 脚本造出僵尸:ps 里出现 Z 176396 176398 [python3] <defunct>;杀掉父进程后僵尸立即消失。如果父进程是 PID 1(systemd),通常会自动收尸不用管;如果父进程是某个服务(比如 Python 守护进程),那要修的是它自己的子进程管理逻辑。
内存视角:free -h 与 available
free -h输出里注意三点:
- available 才是"可用内存"(free + 可回收的 buff/cache)。看到 free 很小别慌,只要 available 还充裕就没问题;
- buff/cache 高是正常现象——Linux 用空闲内存做缓存,需要时会自动释放;
- swap 持续增长才是危险信号:说明物理内存真的不够了,性能会明显下滑。这时候该查谁在泄漏(
ps aux --sort=-%mem),而不是急着加内存。
load average:负载和 CPU 是两回事
load 统计的是"就绪态 + 不可中断睡眠态(D 状态)"的进程数,CPU 使用率只是"CPU 忙多久"。所以会出现一个经典的坑:load 很高但 CPU 空闲率也很高。
这种情况十有八九是 iowait 或 D 状态进程在作祟——磁盘故障、NFS 挂载卡死、内核模块 hang 住都会产生 D 状态进程,它们既不能被信号中断也 kill 不掉。排查方向:
top -bn1 | grep Cpu # 看 wa 列高不高
iostat -x 1 # 磁盘 %util、await
dmesg -T | tail -20 # 查 SCSI timeout、EXT4-fs error 等线索另外对比 load 的三个数:1 分钟远高于 5/15 分钟,说明是刚发生的突发负载,未必持续。
排查路径小结与监控阈值
一套完整的"系统慢"排查路径:
top 看当前谁最耗资源
→ ps 按 CPU/内存排序确认进程身份
→ uptime/load 判断负载是否持续偏高
→ wa 高 → iostat/dmesg 查磁盘;sy 高 → vmstat 查上下文切换
→ 确认后 kill/修代码/扩容常用监控阈值参考(警告 / 严重):
| 指标 | 警告阈值 | 严重阈值 |
|---|---|---|
| CPU load average | 核心数 × 2 | 核心数 × 4 |
| 可用内存 | < 总内存 20% | < 总内存 10% |
| 僵尸进程数 | > 0 | > 5 |
| I/O 等待(%wa) | > 10% 持续 5 分钟 | > 30% 持续 5 分钟 |
生产环境可以把 top -b -n 1 加进 crontab 每 5 分钟存一份快照,出问题时有历史数据可以回溯——排查"慢"最怕的就是当时没留现场。
评论 (0)
暂无评论,快来抢沙发吧!