服务覆盖:昆明·曲靖·玉溪·保山·昭通·丽江·普洱·临沧·楚雄·红河·文山·西双版纳·大理·德宏·怒江·迪庆

磁盘IO突然爆满?别急着加硬件,先查这几个常见坑

eycit 2026-04-24 1 次阅读 系统安装
---

theme: default themeName: "默认主题" title: "磁盘IO突然爆满?别急着加硬件,先查这几个常见坑"


磁盘IO突然爆满?别急着加硬件,先查这几个常见坑

上周接了个客户的技术支持请求,说他们服务器磁盘IO一直100%,业务卡得没法用,已经提了采购申请准备换NVMe硬盘。我让他先别急,远程上去看了一圈,最后零成本把问题解决了。

磁盘IO爆满是运维最常遇到的故障之一,但90%的情况根因都不是硬件性能不够。今天把最常见的几个坑列出来,下次遇到类似问题,按这个清单过一遍,能省不少钱。

第一个坑:日志文件没做轮转

这是最常见也最容易被忽视的问题。

# 查看磁盘IO占用最高的进程

iotop -oP

客户服务器上IO占用最高的是Java进程,进一步排查发现——业务日志文件已经32GB了,每次写入都是对一个大文件的追加操作,而且还有个tail命令一直在读这个文件做实时监控。

32GB的文件,哪怕是追加写入,操作系统也要频繁更新元数据。加上tail实时读,磁盘磁头(如果是HDD)或者SSD的读写交替,性能急剧下降。

解决方案很简单:

# 安装logrotate(大多数系统已预装)

配置日志轮转

cat > /etc/logrotate.d/myapp << 'EOF' /var/log/myapp/app.log { daily rotate 30 compress delaycompress missingok notifempty copytruncate maxsize 500M } EOF

手动触发一次

logrotate -f /etc/logrotate.d/myapp

关键参数解释:

  • `copytruncate`:先复制再截断,不需要重启应用
  • `maxsize 500M`:超过500M就轮转,不等到第二天
  • `compress + delaycompress`:压缩旧日志,但保留最近一份不压缩

光是加了日志轮转,IO就降了40%。

第二个坑:数据库的脏页刷盘策略

这个坑在MySQL上特别常见。看个例子:

# 查看MySQL的刷盘相关参数

mysql -e "SHOW VARIABLES LIKE 'innodb_io_capacity%';" mysql -e "SHOW VARIABLES LIKE 'innodb_max_dirty_pages_pct%';" mysql -e "SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_wait_free';"

客户的结果:

innodb_io_capacity = 200         -- 默认值,太低了

innodb_io_capacity_max = 400 -- 也太低 innodb_max_dirty_pages_pct = 90 -- 脏页比例到90%才加速刷盘 Innodb_buffer_pool_wait_free = 847293 -- 这个值很大,说明频繁等空闲页

问题很清楚:`innodb_io_capacity`设置太低,InnoDB的刷盘速度跟不上脏页产生速度。当脏页积攒到90%时,InnoDB会进入"暴力刷盘"模式,疯狂占用IO,把其他读写请求全部挤掉。

优化方案:

-- SSD盘建议设置

SET GLOBAL innodb_io_capacity = 2000; SET GLOBAL innodb_io_capacity_max = 4000; SET GLOBAL innodb_max_dirty_pages_pct = 75; SET GLOBAL innodb_max_dirty_pages_pct_lwm = 50;

原理: 提高IO能力上限,让InnoDB平时就以较高速度平稳刷盘,避免脏页积攒后的"暴力刷盘"。`lwm`(低水位线)也很重要——设置成50%意味着脏页超过50%就开始温和加速,到75%全力刷盘,整个过程更平滑。

改完这组参数,IO波动从"过山车"变成了"平缓曲线",峰值降了一半。

第三个坑:swap频繁换入换出

这个很多人知道要避免,但经常忘记检查。

# 查看swap使用情况

free -h

查看swap换入换出频率

vmstat 1 10

客户的输出:

procs -----------memory---------- ---swap-- -----io----

r b swpd free buff cache si so bi bo 3 1 2048000 123456 89012 456789 125 89 256 456

`si`(swap in)和`so`(swap out)不为0,说明系统在频繁使用swap。每秒125页换入、89页换出,这意味着大量内存页在物理内存和磁盘之间来回搬运,磁盘IO当然爆了。

为什么会有这么多swap?查看进程内存占用:

ps aux --sort=-%mem | head -20

发现有个Python数据处理的脚本占了20GB内存,而服务器总共才32GB。这个脚本是定时任务,每天凌晨跑一次,跑完后内存没释放完,导致白天的业务进程被迫用swap。

解决方案:

# 1. 限制Python脚本的内存使用

ulimit -v 8388608 # 限制为8GB

2. 调整swappiness(不建议完全关闭swap)

sysctl vm.swappiness=10 # 默认60,改小让它尽量不用swap

3. 更好的方案:让Python脚本跑完后主动释放内存

在脚本结尾加上:

import gc gc.collect()

第四个坑:大量小文件的随机读写

这个坑比较隐蔽。客户的服务器上有个文件上传服务,用户上传的文件直接存本地磁盘,每个文件几KB到几百KB不等,但文件数量巨大——一个目录下超过50万个文件。

# 统计目录下的文件数
find /data/uploads -type fwc -l

523847

查看目录大小

du -sh /data/uploads

2.3G

查看文件系统inode使用率

df -i

50多万个小文件,每次访问都是一次随机IO。Linux的ext4文件系统在目录下文件数过多时,查找效率会急剧下降(即使有dir_index特性)。

解决方案不是加硬件,而是改变存储方式:

# 方案1:分目录存储(按日期/哈希分层)

/data/uploads/2026/04/24/ab/cd/abcdefg.jpg

两级哈希目录,每个子目录不超过1000个文件

方案2:换用对象存储(推荐)

小文件场景天然适合对象存储,本地只存热数据

方案3:如果必须本地存储,用XFS替代ext4

XFS在大量小文件场景下性能更好

mkfs.xfs -f /dev/sdb1

客户最终选择了方案1+方案2的组合:新文件走对象存储,历史文件按哈希重分布到子目录。IO降了60%。

第五个坑:定时任务扎堆执行

这个坑很常见但很难发现,因为它是周期性的。

# 查看系统定时任务

crontab -l cat /etc/crontab ls /etc/cron.d/

客户的crontab里有6个定时任务,全部设在了凌晨2点执行:

0 2   * /opt/backup/full.sh

0 2 * /opt/scripts/log_clean.sh 0 2 * /opt/scripts/db_dump.sh 0 2 * /opt/scripts/report_gen.sh 0 2 * /opt/scripts/data_sync.sh 0 2 * /opt/scripts/log_analysis.sh

六个任务同时跑,全都在疯狂读写磁盘。特别是`full.sh`(全量备份)和`db_dump.sh`(数据库导出),两个加起来每秒读写超过200MB。

解决方案:错峰执行。

0 2   * /opt/backup/full.sh

30 2 * /opt/scripts/log_clean.sh 0 3 * /opt/scripts/db_dump.sh 30 3 * /opt/scripts/report_gen.sh 0 4 * /opt/scripts/data_sync.sh 30 4 * /opt/scripts/log_analysis.sh

快速排查清单

最后给你一个清单,磁盘IO爆满时按顺序检查:

排查项命令常见问题
IO占用最高的进程`iotop -oP`日志写入、数据库刷盘
大文件`find / -type f -size +1G`未轮转的日志、临时文件
Swap使用`free -h && vmstat 1 5`内存不足导致swap换页
MySQL刷盘参数`SHOW VARIABLES LIKE 'innodb_io%'`io_capacity太低
文件数量`df -i && find -type f \wc -l`小文件过多
定时任务`crontab -l`任务扎堆
磁盘调度器`cat /sys/block/sda/queue/scheduler`HDD用deadline,SSD用noop/mq-deadline

客户的案例最终效果:零硬件成本,IO使用率从95%降到35%。那个NVMe采购申请,撤了。

做IT这么多年,见过太多"早知道就好了"的情况。

希望这篇文章能帮你少走弯路。如果真的遇到问题,别一个人扛着——易云城IT服务随时待命。

📞 服务热线:13708730161 💬 微信:eyc1689 📧 邮箱:service@eycit.com 🌐 https://www.eycit.com

您身边的IT专家。

上一篇
线上服务突然卡死?我用这五步排查法30分钟定位根因...
下一篇
Nginx并发从2000到20000,我只改了这6个配置...