VPS 变慢时,CPU 不一定是主因。
有时你打开 top,发现 CPU 使用率不高,但 %wa 很高;SSH 输入命令有延迟,网站接口慢,数据库查询拖,解压和写日志也卡。这种情况很可能是磁盘 I/O 卡住了。
磁盘 I/O 问题最容易误判:有人以为是程序性能差,有人以为是网络慢,也有人直接重启。正确做法是先确认是不是 iowait,再找哪个进程在读写,最后判断是日志、数据库、Docker、swap、备份任务,还是服务商底层存储争用。
第一步看 top:
top
在 CPU 那一行里看 %wa。如果 %wa 长时间很高,说明 CPU 有不少时间在等磁盘 I/O 完成。
也可以用:
vmstat 1
重点看:
wa:CPU 等 I/O 的比例;bi/bo:块设备读写;r:等待 CPU 的进程;b:不可中断睡眠,常见于等待 I/O。
如果 wa 很高,b 也不低,机器体感卡顿,就不要只盯着应用日志了。
安装工具:
sudo apt install sysstat -y
或 RHEL 系:
sudo dnf install sysstat -y
看磁盘扩展指标:
iostat -x 1
重点看这些列:
%util:设备忙碌程度;await:I/O 请求平均等待时间;r/s、w/s:每秒读写请求数;rkB/s、wkB/s:每秒读写吞吐;aqu-sz:平均队列长度。
简单判断:
%util长时间接近 100%,说明磁盘很忙;await明显升高,说明 I/O 等待变长;aqu-sz长时间偏高,说明请求在排队;- 吞吐不高但 await 很高,可能是随机 I/O、IOPS 上限或底层存储延迟。
不要只看一个值。iowait 高只能说明 CPU 在等 I/O,不能直接证明“硬盘坏了”。要结合 iostat 和进程级读写一起看。
安装:
sudo apt install iotop -y
运行:
sudo iotop -oPa
参数含义:
-o:只显示正在产生 I/O 的进程;-P:按进程聚合,而不是线程;-a:显示累计读写量。
常见会出现在前面的进程:
mysqld/mariadbd/postgres:数据库读写;dockerd/containerd:容器日志或镜像层;journal/rsyslogd:系统日志写入;backup/tar/gzip/rsync:备份压缩同步;updatedb/apt/dpkg:索引或安装任务;- 应用进程:疯狂写日志或临时文件。
如果 iotop 里一个进程持续大量写入,先不要急着杀进程,先确认它在写什么。
iotop 看现场很好用,pidstat 更适合看一段时间趋势。
pidstat -d 1
看某个进程:
pidstat -d -p PID 1
重点看:
kB_rd/s:每秒读取;kB_wr/s:每秒写入;kB_ccwr/s:被取消的写入。
如果某个应用写入一直很高,再结合它的日志目录、上传目录、缓存目录查。
先看大目录:
sudo du -xh /var/log --max-depth=1 | sort -h
看最近变化快的日志:
sudo find /var/log -type f -printf '%s %p\n' | sort -n | tail -n 20
实时看某个日志是否疯狂增长:
sudo tail -f /var/log/nginx/error.log
常见场景:
- Nginx 反复记录 upstream 错误;
- 应用异常栈刷屏;
- Docker 容器 stdout/stderr 无限制写日志;
- fail2ban、认证失败、爬虫访问导致日志暴涨;
- debug 日志忘了关。
如果是 Docker 日志,可以看:VPS Docker 占满磁盘怎么办。那篇讲磁盘占用,这篇重点是 I/O 卡顿;两个问题经常一起出现。
如果 iotop 里是 MySQL、MariaDB 或 PostgreSQL,不代表数据库“有问题”,可能是业务真的在读写,也可能是慢查询、索引缺失、临时表、checkpoint、vacuum 或备份。
先看系统层面:
sudo iotop -oPa
pidstat -d -p $(pidof mysqld) 1
pidstat -d -p $(pidof postgres) 1
再看数据库日志:
sudo journalctl -u mysql -n 100 --no-pager
sudo journalctl -u mariadb -n 100 --no-pager
sudo journalctl -u postgresql -n 100 --no-pager
常见原因:
- 没索引导致大量随机读;
- 查询生成大临时表;
- 备份任务和业务高峰撞车;
- binlog / WAL 写入压力高;
- 磁盘快满后数据库写入变慢;
- 内存不足导致缓存命中低。
数据库连接不上或服务启动失败,可以分别看 MySQL、PostgreSQL、Redis 的专项文章;这里先定位 I/O 是不是数据库造成的。
小内存 VPS 很容易遇到 swap 抖动。表面上是磁盘 I/O 高,根因是内存不够,系统频繁把内存页换进换出。
检查:
free -h
swapon --show
vmstat 1
在 vmstat 里看:
si:swap in;so:swap out。
如果 si/so 持续不为 0,同时 %wa 高,说明 swap 参与了卡顿。
临时缓解可以停掉不必要服务、降低并发、错开任务。长期还是要优化内存、加缓存、升级套餐,或者把数据库和应用拆开。
很多 I/O 高峰是自己制造的。
例如:
tar -czf backup.tar.gz /var/www /var/lib/mysql
rsync -av /data remote:/backup
mysqldump app > app.sql
docker save image > image.tar
这些任务如果和业务高峰、数据库写入、日志切割一起发生,VPS 很容易卡。
排查定时任务:
crontab -l
sudo crontab -l
systemctl list-timers --all
看最近日志:
journalctl --since "2 hours ago" --no-pager
如果是定时任务触发导致,可以参考:VPS 定时任务不执行怎么办,里面的排查方法同样适合找“谁在定时制造 I/O”。
Docker 场景下,I/O 高经常来自两个地方:
- 容器日志疯狂写入;
- overlay2 层频繁写临时文件。
先看容器状态:
docker ps --size
看日志大小:
sudo du -xh /var/lib/docker/containers --max-depth=2 | sort -h | tail -n 20
看某个容器日志是否刷屏:
docker logs 容器名 --tail 100
如果业务允许,给 Docker 配日志轮转,例如 json-file 的 max-size 和 max-file。不要让一个异常容器把宿主机磁盘和 I/O 都拖死。
如果你已经确认:
- 没有明显大写入进程;
- 数据库和日志压力不高;
- swap 没有明显抖动;
- 备份任务没在跑;
- 但
await长时间高、%util高、SSH 和所有应用都一起卡; - 晚高峰更明显,或同节点用户也反馈慢;
那就可能是宿主机存储争用、IOPS 限制或邻居影响。
这时不要只发一句“磁盘慢”。给服务商工单附上证据:
date
uptime
vmstat 1 10
iostat -x 1 10
sudo iotop -oPa -b -n 5
free -h
df -h
如果你做 fio 测试,注意不要在业务高峰对生产盘乱压测。小 VPS 上 fio 很容易进一步拖慢业务。
遇到 VPS 磁盘 I/O 高或 iowait 高,按这个顺序查:
top看%wa是否持续偏高。vmstat 1看wa、b、bi/bo、si/so。iostat -x 1看%util、await、aqu-sz。iotop -oPa找正在读写的进程。pidstat -d 1看进程读写趋势。du -xh /var/log查日志是否暴涨。- 检查数据库、Docker、备份、压缩、同步任务。
free -h、swapon --show、vmstat判断 swap 抖动。- 错峰重任务,限制日志,优化数据库查询和缓存。
- 没有本机原因时,带
iostat/vmstat/iotop证据找服务商。
VPS 磁盘 I/O 高,不要只看 CPU,也不要直接重启。先用 top 和 vmstat 确认是不是 iowait,再用 iostat -x 判断磁盘延迟和队列,最后用 iotop、pidstat 找到具体进程。
大多数问题最后会落到日志暴涨、数据库随机读写、Docker 日志、swap 抖动、备份任务撞车,或者宿主存储争用。能定位到进程,就先修本机;定位不到本机原因,再拿完整指标找服务商,这样工单才有说服力。
