CPU 飙到 100% 怎么办?磁盘 IO 慢是谁的锅?内存到底被谁吃光了?掌握 top/iostat/vmstat/strace 四件套,让你面对性能问题不再慌。
服务器又卡了?别急着重启,先用这三板斧看看谁在搞鬼。
接到报警说服务响应慢,SSH 上去一看 uptime 负载 20+,CPU 风扇嗡嗡响——这时候怎么办?
很多人的第一反应是重启。但重启只是掩盖问题,下次还会复现。今天聊一套标准诊断流程,以后遇到性能问题,按这个顺序排查就对了。
第一板斧:负载速览 — uptime + top/htop
上服务器先看三件事:谁在、负载多少、谁在吃资源。
# 1. 看负载和在线用户uptime# 输出: 16:30:45 up 30 days, 2 users, load average: 2.15, 1.80, 1.50# 2. 看进程全景top
uptime 的三个数字是 1 分钟、5 分钟、15 分钟的平均负载。这个值是等待 CPU + 等待 IO 的进程数之和,不是 CPU 使用率。很多人搞混这两个概念。
一个 4 核 CPU,负载 2.0 说明还不到一半,负载 8.0 说明已经严重过载了。
关键判断:如果负载高但 CPU 使用率低(idle 很高),说明瓶颈在 IO,不是计算——CPU 在等磁盘。
top 里重点盯这几个指标:
如果你用 htop,颜色就更加直观了——蓝绿是正常,红色是高负载,自己调色看着舒服。最关键的是 htop 支持鼠标点击排序和直接 F9 杀进程,比 top 顺手太多。
实战:发现 %wa 持续 30%+,%us 才 10%。说明 CPU 根本不忙,全在等磁盘。别急着找哪个进程吃 CPU,先去看 IO。
第二板斧:IO 深度分析 — iostat + iotop
确认了 IO 有问题,下一步精确定位。
# 安装: apt install sysstatiostat -x 1 3
iostat -x 的输出里,关注这几个字段:
| | |
|---|
r/sw/s | | 普通 SATA SSD 随机读写能到几万 IOPS,如果才几百但 CPU 在等,说明队列拥堵 |
rkB/swkB/s | | 顺序读写 SATA SSD 能到 500MB/s,如果几十 MB/s 就到顶了,可能磁盘老化 |
await | | 最关键指标,SATA SSD 正常 < 5ms,> 50ms 说明严重拥堵 |
%util | | 接近 100% 就是瓶颈。但注意 NVMe 的 %util 只看时间不看并发,可能不准 |
# 知道哪块盘慢了,再找哪个进程在疯狂读写iotop -o
-o 只显示有 IO 活动的进程,一眼就能看到谁在疯狂读写。
常见场景:
await 爆高,r/s 不大 — 大量随机读写,比如数据库在全表扫描却没有索引,磁盘在做无用功w/s 很高,wkB/s 不大 — 大量小文件写入,比如日志疯狂刷屏没做轮转。一个 logrotate 能解决的事,别让磁盘硬扛%util 持续 100% — 磁盘真的扛不住了。短期方案:加 noatime 挂载、调大 dirty page 刷新间隔;长期方案:换 SSD 或做 RAID
第三板斧:内存追凶 — free + vmstat + smem
内存问题比 CPU 和 IO 更隐蔽,因为 Linux 的内存管理策略经常让人误判。
free -h
total used free shared buff/cache availableMem: 62Gi 45Gi 2.0Gi 1.0Gi 14Gi 15GiSwap: 8.0Gi 3.0Gi 5.0Gi
关键误区:free 列很小不代表内存不够——Linux 会把空闲内存拿来做缓存(buff/cache),这是好事。真正要看的是 available 列,它才是「现在有多少内存可以给新进程用」。
available 接近 0 且 swap 在增长?那就是真缺内存了。
# 看内存换入换出vmstat 1
vmstat 输出里盯这两个:
如果 si/so 持续非零,有两个方向:
方向一:找吃内存大户
# 按 RSS(物理内存)排序ps aux --sort=-%mem | head -20# 或者更直观的smem -t -p -s rss
smem 比 ps 好在它区分了独占内存(USS)和共享内存(PSS)——一个进程说占了 2G,可能其中有 1.5G 是共享库,实际独占只有 500M。用 USS 排序才能找到真凶。
方向二:查内存泄漏
# 看某个进程的内存趋势whiletrue; do ps -o pid,rss,comm -p <PID> >> mem_trace.logsleep 10done
观察 RSS 是否单调增长,如果一直在涨且从不下降,大概率是内存泄漏。Java 应用常见,Go 程序相对少见但也不是没有(goroutine 泄漏)。
番外:进程行为分析 — strace/lsof
前三板斧定位了谁在吃资源,但还需要知道它在干什么。
# 看进程打开了哪些文件lsof -p <PID># 看谁在占用某个端口lsof -i :8080# 追踪系统调用strace -p <PID> -c # 统计模式:看哪种系统调用最耗时strace -p <PID> -e trace=network # 只看网络相关strace -p <PID> -T # 显示每次调用的耗时
strace -c 特别实用——运行 30 秒后 Ctrl+C,它会告诉你这 30 秒里进程在干什么:
% time seconds usecs/call calls errors syscall------ ----------- ----------- --------- --------- ---------------- 99.21 5.832105 1240 4702 poll 0.45 0.026735 18 1466 read 0.22 0.012924 14 900 write
一眼看出这进程 99% 的时间在 poll 等待,说明它在等某个文件描述符就绪——可能是网络 IO 慢,也可能是管道阻塞。
诊断流程图
把这个流程固化下来,以后遇到性能问题就不用现场回想该用什么命令了:
负载告警 │ ▼uptime → 负载高吗? │ ├─ 高 ──→ top/htop ──→ CPU 高? │ │ │ ┌────┴────┐ │ │ │ │ us高 sy高 │ │ │ │ ps找进程 strace │ 看业务 查系统调用 │ ├─ %wa 高 ──→ iostat ──→ iotop 找进程 │ └─ swap 活跃 ──→ free → smem 找大户 → 扩内存或杀进程
一句话总结
服务器卡了别重启,uptime → top → iostat → free → strace,五步走完原因基本就清楚了。
把这几个命令记熟,下次同事喊「服务器又挂了」的时候,你已经把根因排查出来了。那种感觉,比重启服务器爽多了。
下期预告:既然密码要记的越来越多,为什么不自己搭一个密码管理器?下期聊聊 Vaultwarden 自建方案,Bitwarden 兼容、免费、跑在自家 K3s 集群上,全家设备同步。