先看整体,再钻细节
服务变慢时,最忌讳上来就 top 看一眼然后猜。CPU 高、内存高、磁盘满、IO 卡住,表现都是"接口慢",但处理方式完全不同。正确的顺序是:先看整体负载和资源水位,判断瓶颈在 CPU、内存还是磁盘,再定位到具体进程和线程。
这篇文章按 CPU、内存、磁盘三块整理常用命令,最后给一条完整的排查路径。命令不用背,知道每个工具回答什么问题就行。
CPU 与负载
uptime
# 12:00:00 up 30 days, load average: 8.20, 6.10, 4.30
nproc # 逻辑核数
top # 动态观察,按 1 展开每个核,按 P 按 CPU 排序
load average 的三个数字是 1 分钟、5 分钟、15 分钟的平均负载。判断标准是和核数比较:4 核机器 load 长期在 8 以上,说明任务在排队;但 load 高不一定是 CPU 忙,也可能是大量进程卡在 IO 上。
top 里重点看这几列:
%us:用户态 CPU,业务代码消耗;%sy:内核态 CPU,系统调用、上下文切换;%wa:等待 IO 的 CPU 比例,高说明磁盘是瓶颈;%si:软中断,网络流量大时可能升高。
进一步拆到每个核和每个进程:
mpstat -P ALL 1 # 每个核的使用率,看是否单核打满
pidstat -u 1 5 # 每 1 秒采样,共 5 次,按进程看 CPU
pidstat -w 1 5 # 上下文切换
单核打满、其他核空闲,常见于 GC 线程、单线程任务、锁竞争。这种情况加机器没用,得看代码。
内存
free -h
# total used free shared buff/cache available
# Mem: 15Gi 9.0Gi 0.5Gi 0.2Gi 6.0Gi 5.8Gi
cat /proc/meminfo | head -20
看内存不要只盯 free。Linux 会把空闲内存拿去做页缓存,free 很小是正常的,关键看 available——它表示"还能给新进程用多少"。available 长期低于总量的 10%,才需要警惕。
如果怀疑内存泄漏或者被 OOM 杀过进程:
dmesg -T | grep -i "out of memory"
journalctl -k | grep -i oom
被 OOM Killer 选中的进程会在内核日志里留下记录,包括进程名、PID 和当时的 memory 使用情况。容器环境还要看 docker inspect 里的 OOMKilled。
磁盘与 IO
df -h # 分区使用率
df -i # inode 使用率
du -sh /data/* | sort -rh | head -20
iostat -x 1 # 磁盘 IO,重点看 %util、await、aqu-sz
iotop -oP # 按进程看 IO
df 显示磁盘满但 du 加起来对不上,通常是文件被删除但进程还持有句柄:
lsof +L1 # 列出已删除但仍被打开的文件
重启对应进程或者清空句柄,空间才会释放。inode 满也会导致"写不进去",df -h 看起来还有空间,df -i 已经 100%,常见于大量小文件。
iostat -x 1 里关注三个指标:%util 接近 100% 说明磁盘饱和;await 是平均等待时间,机械盘超过 20ms、SSD 超过 5ms 就偏慢;aqu-sz 是排队长度,持续大于 2 说明请求在排队。
常见坑
1. 把 load 高当成 CPU 高
load 统计的是可运行和不可中断状态的进程数,IO 阻塞(D 状态)也会计入。load 很高但 CPU 空闲,先看 vmstat 的 b 列和 %wa。
2. 看 free 判断内存不足
free 小、buff/cache 大是正常现象。判断内存压力看 available,或者看有没有发生 swap(vmstat 的 si、so 持续非零)。
3. 被 top 的 %CPU 误导
top 里单个进程的 %CPU 可以超过 100%,因为是所有核累计。一个进程 400% 在 8 核机器上只占一半,不要看到超过 100 就以为异常。
4. 只采样一次就下结论
CPU、IO、内存都是动态的。top 按一次 q 退出看到的只是一个瞬间,用 vmstat 1、pidstat 1 连续观察几十秒,才能看出趋势。
5. 容器里看到的是宿主机数据
容器默认共享宿主机的 /proc,top、free 显示的是整台机器的资源。要看容器自身的限制,用 docker stats 或者 cgroup 文件。Kubernetes 环境同理。
6. df 和 du 不一致
前面说过,删除未释放的文件、挂载覆盖、namespace 隔离都会导致两者不一致。先 lsof +L1,再检查挂载点。
7. iostat 第一次输出不准
iostat 第一次输出的是自开机以来的平均值,不是当前值。加 1 参数后看第二次及以后的结果。
排查步骤
一条比较稳的路径:
uptime和top看整体负载、CPU、内存水位;vmstat 1区分是 CPU 忙、IO 等待还是内存交换;- CPU 高用
pidstat -u定位进程,再top -Hp <pid>定位线程; - IO 高用
iostat -x确认哪块盘,iotop -oP定位进程; - 内存紧张看
dmesg有没有 OOM,free -h看available; - 磁盘写不进去看
df -h、df -i、lsof +L1; - Java 应用把线程 ID 转成十六进制,去
jstack里找对应栈。
命令只是工具,关键是先判断瓶颈类型,再往下钻。最怕的是一上来就重启,把现场毁了。
评论