[Linux 性能 02] 使用 Htop 与 Iotop 诊断"性能元凶"
2026-08-14 · DevCraft Studio
网页打不开、SSH 卡成 PPT?别急着重启机器。用 htop 看负载、用 iotop 抓硬盘读写狂魔、用 dmesg 查 OOM 被杀、用 ss 揪异常连接,四步把"元凶"找出来。每个步骤都给真实可复制的命令。
相信不少朋友都遇到过这种场面:早上还好好的一台 VPS,下午突然网页打不开、SSH 连上去敲命令都卡半天。第一反应往往是"重启大法好"——但重启只是把问题按了暂停键,根因没找到,过两天它还会回来。
这篇就用大白话,教你在 5 分钟里用四个工具把"元凶"揪出来:htop 看 CPU 负载、iotop 看硬盘读写、dmesg 查内存被吃光、ss 查异常网络连接。命令都给好了,直接复制就能用。
先别慌:5 分钟定位法的思路
系统变慢,本质上就那几类原因,跟医生看病先分科一个道理:
- CPU 被打满:有进程在疯狂算,别人抢不到计算资源;
- 硬盘 I/O 卡住:CPU 其实很闲,但全在干等硬盘读写(这叫 iowait),表现出来就是"卡";
- 内存耗尽:系统为了活命,把最占内存的进程杀掉了(OOM Killer),服务莫名其妙消失;
- 网络被占满:有异常连接在疯狂进出流量,正常请求挤不进去。
下面四步,正好对应这四种情况。按顺序来,基本跑不出这个范围。
第一步:htop 看 CPU 负载和 Load Average
先看整体。绝大多数 Linux 发行版没预装 htop,先装上:
# Debian / Ubuntu
sudo apt install htop
# CentOS / Fedora / Rocky
sudo dnf install htop装好直接运行:
htop进来你会看到顶部一排彩色的条,和下面一长串进程。先盯顶部这几个东西:
1. Load average(负载),通常长这样:Load average: 2.50, 1.80, 1.20。这仨数分别是「最近 1 分钟 / 5 分钟 / 15 分钟」的平均负载。
- 粗略经验值:负载数除以你的 CPU 核心数,小于 1 算轻松,大于 1 就开始排队,远大于核心数(比如 4 核机器负载 20)那就是严重过载了。
- 1 分钟的比 15 分钟的高很多,说明是刚发生的突发;反过来说明问题持续很久了。
2. CPU 条,看颜色。绿色是普通进程,红色是内核态,蓝色是低优先级。如果 CPU 条几乎全是绿的、且接近 100%,那是有进程在猛吃 CPU。
3. 内存条和 Swap 条。Swap(交换分区)要是被用满了,说明物理内存早不够了,系统在拿硬盘当内存用——这会非常非常慢。
分清两种"卡":
- CPU 满载型:CPU 条红/绿爆满 + 负载高 + 某个进程 CPU% 特别高。元凶就是那个进程。
- 进程死锁 / I/O 等待型:负载很高,但 CPU 条却有很多空闲(绿色不满),这时候大概率是卡在硬盘 I/O 上了,别在 CPU 上找原因——跳到第二步。
htop 里几个好用的快捷键:按 P 按 CPU 排序、M 按内存排序、F4 过滤进程名、F9 发信号杀进程(先用 15 SIGTERM,不行再 9 SIGKILL)。
如果机器卡到 htop 都打不开,先用最朴素的 top 顶一下:
top按数字 1 展开每个核心,%wa 那一列就是 iowait,先记着这个,下一步要用。
第二步:看 iowait,用 iotop 抓硬盘读写狂魔
如果你的机器是"负载高、CPU 却闲",那九成是硬盘 I/O 卡住了。CPU 其实没事干,全在干等硬盘回应。
先确认 iowait 是不是真的高。在 top 里看 %Cpu(s) 那行的 wa 值;或者更直观:
vmstat 1看 wa 列(iowait 百分比)和 b 列(被 I/O 阻塞的进程数)。如果 wa 长期高于 20%、b 持续大于 0,基本坐实是 I/O 问题。想看每个核心:
mpstat -P ALL 1%iowait 列如果普遍明显非零、或者某个核超过 20%,就是它在等硬盘。
抓出"读写狂魔",用 iotop:
sudo apt install iotop # Debian/Ubuntu
sudo iotop -o-o 参数很关键,它只显示正在做 I/O 的进程,不然满屏都是空闲的内核线程,啥也看不清。运行几十秒,排在最上面、DISK READ / DISK WRITE 和 IO% 特别高的那个 PID,就是元凶。
比如你看到某个 mysqld 或者 rsync 或者一个 Python 脚本占了 90% 的磁盘带宽,那就对上号了。
想再精确点,看是哪块盘在忙:
iostat -x 1关注两列:%util(设备繁忙程度,接近 100% 就是打满了)和 await(每次 I/O 平均等待毫秒数,SSD 上超过 50ms 就很危险,超过 200ms 基本是灾难)。如果 sda 的 %util 是 99%、await 800ms,那这块盘就是瓶颈,没跑了。
常见的"硬盘读写狂魔"都有谁?
- 数据库在猛写:比如有人把日志级别开成 DEBUG,每秒写几十 MB;
- 备份 / 同步脚本在跑:rsync、tar 在业务高峰没避开;
- swap 被用满疯狂交换:内存不够,系统拿硬盘当内存,慢到怀疑人生;
- 某个脚本在扫大目录:爬虫、日志分析在扫几百万个小文件。
找到进程后,别急着 kill。先看它是不是该在此时运行——如果是备份脚本,挪到凌晨低峰就行;如果是日志爆炸,调低日志级别;如果是 swap 问题,加内存或关掉 swap。对症处理,比无脑杀进程有用。
第三步:检查 OOM Killer 杀进程日志
还有一种"卡"的表现很诡异:某个服务(比如 MySQL、网站)莫名其妙没了,日志里啥报错都没有。这大概率是被 OOM Killer(内存溢出杀手)干掉了。
Linux 内存 + Swap 都耗尽时,内核不会让你整个系统死机,而是挑一个"最胖"的进程杀掉腾内存——这就是 OOM Killer。它干完活会在内核日志里留记录,查一下就知道:
dmesg -T | grep -i "killed process"或者更宽泛地搜:
dmesg | grep -i oom如果是 systemd 系统(现在绝大多数都是),也可以这样:
sudo journalctl -k | grep -i oom看到的输出大概长这样:
[Tue Aug 14 15:33:12] Out of memory: Killed process 28412 (mysqld) total-vm:4289012kB, anon-rss:4102000kB, file-rss:0kB几个重点:
Killed process 28412 (mysqld):被杀的 PID 和进程名,一眼看出是谁;anon-rss:4102000kB:它被杀时占了多少物理内存(这里约 4GB),说明当时内存确实绷不住了;- 时间点:帮你对照是不是和"服务消失"的时刻对得上。
有些老机器日志被轮转清掉了,还可以翻历史文件:
# Debian / Ubuntu
grep -i "out of memory" /var/log/kern.log*
# CentOS / RHEL
grep -i "out of memory" /var/log/messages*确认是 OOM 之后,下一步是看现在内存还剩多少、谁在吃:
free -h
ps aux --sort=-%mem | head -20free -h 看整体,ps 那行按内存占用排前 20 的进程一目了然。常见元凶:PHP-FPM 进程数太多、MySQL 的 innodb_buffer_pool_size 设太大、某个 Java 程序堆内存没限制。
根因往往是"机器内存本来就紧(比如 1GB),还硬跑了好几个服务"。这时候要么优化各服务的配置把内存压下来,要么…老实加内存。临时救命可以调 OOM 优先级保护关键进程(比如 MySQL):
# 找到 MySQL 的 PID
pgrep -a mysqld
# 降低它的 OOM 分数(数值越低越不容易被杀),重启后失效
echo -500 | sudo tee /proc/<PID>/oom_score_adj但说白了,这只是创可贴。真要解决,还是得让内存够用。
第四步:用 ss / netstat 排查异常连接
最后一种情况:CPU、硬盘、内存看着都正常,但机器就是慢、流量跑得飞快。这就要怀疑有异常连接在疯狂消耗带宽——可能是被扫端口、有异常进程在往外传数据,或者遭遇了某种流量攻击。
现代 Linux 首选 ss(netstat 已经过时了,但很多机器还能用)。先看哪些端口在监听、对应什么进程:
sudo ss -tulpn-t TCP、-u UDP、-l 只听监听中、-p 带进程名、-n 不解析域名直接显示数字端口。这一行能帮你确认:有没有不该暴露的端口开着?进程名对不对得上?
然后看当前所有"已建立"的连接,揪出流量异常:
sudo ss -tn state ESTABLISHED想统计每个远程 IP 占了多少连接,这是发现"被扫 / 被连接耗尽"最实用的命令:
sudo ss -tn state ESTABLISHED | awk '{print $4}' | cut -d: -f1 | sort | uniq -c | sort -rn输出里如果某个 IP 占了成百上千个连接,那基本就是异常——可能是有人在暴力破解 SSH、或者你的某个服务被刷了。配合看连接总数:
sudo ss -tn state ESTABLISHED | wc -l如果连接数高得离谱(几千上万),机器卡顿就解释得通了。
还在用 netstat 的话,等价命令是:
netstat -antp | grep ESTABLISHED发现异常 IP 怎么办?简单粗暴可以先封:
# 用 iptables 临时封掉某个恶意 IP
sudo iptables -A INPUT -s 1.2.3.4 -j DROP更规范的做法是装个 fail2ban,自动封掉反复暴力破解的 IP,省心不少。另外,确认一下是不是自己的服务(比如没限速的下载、被刷的 API)在制造流量,该限流限流、该关就关。
一个速查清单(建议收藏)
把上面的命令压成一张表,出事了对着敲就行:
| 怀疑原因 | 先看什么 | 关键命令 | | --- | --- | --- | | CPU 打满 | htop 顶部 CPU 条、Load | htop(按 P 排序) | | 硬盘 I/O 卡 | top 的 %wa、vmstat 的 b | vmstat 1、sudo iotop -o | | 内存耗尽被杀 | dmesg OOM 记录 | dmesg -T \| grep -i "killed process" | | 异常连接 / 流量 | 监听端口 + 连接数 | sudo ss -tulpn、ss -tn state ESTABLISHED \| wc -l |
记住排查顺序:先看整体负载(htop)→ 再分 CPU 还是 I/O(iotop / vmstat)→ 查内存是否被 OOM(dmesg)→ 最后查网络(ss)。大部分"卡死"都能在这四步里找到答案。
结论
VPS 突然变慢别慌,也别无脑重启。它"卡"的背后,无非是 CPU、硬盘、内存、网络这四样里某一样到了极限。用 htop 看负载分清是算不过来还是等硬盘,用 iotop 抓出读写狂魔,用 dmesg 查是不是被 OOM 杀了进程,用 ss 揪出异常连接——四步走完,元凶基本跑不掉。
把这些命令存一份在记事本里,下次机器再抽风,照着敲一遍,5 分钟定位、对症处理,比重启之后提心吊胆等它再挂,强太多了。
延伸阅读
更多相关攻略推荐:连云厂商也看不到你的数据?机密计算(Confidential Com、被割裂的"云上互联网":数据主权(GDPR)、本地化存储与主权云(S、为什么你自己 VPS 发的邮件总进垃圾箱?邮件协议(SPF、DKIM、百兆带宽如何流畅看 4K?视频切片(HLS/DASH)、AVIF 压、告别繁琐密码:OAuth 2.0、SSO 单点登录与 Passkey。