当一台Linux服务器出现响应迟缓、SSH登录卡顿、应用处理速度下降、数据库查询延迟飙升甚至出现系统假死时,磁盘IO很可能已经接近极限。与CPU、内存不同,磁盘性能往往是服务器最脆弱的资源,一旦被某个进程密集读写,就会成为整个系统的瓶颈。理解如何科学、系统地排查 IO 利用率高的问题,是运维工程师与后端开发必备的技能。排查思路需要遵循“系统层 → 进程层 → 文件系统层 → 磁盘层”的原则,从宏观到微观逐步定位故障根因。
一般的排查会先从系统整体状况入手。使用 top 命令,可以在第一时间确认是否存在磁盘阻塞。执行 top 后,如果发现 %wa(iowait)数值长期维持在 20% 以上,或 Load Average 持续攀升但 CPU 使用率并不高,说明大量进程正在等待磁盘响应。此类现象表明问题确实集中在 IO,而非应用本身的 CPU 负载或网络操作。
在确认 IO 异常后,需要进一步判断磁盘层面的繁忙程度。借助 iostat 命令可以快速获得面向磁盘的核心指标。安装 sysstat 工具后执行:
iostat -x 1 5
输出中最关键的参数是 %util,它反映了磁盘的忙碌程度。当 %util 逼近 100% 时,磁盘已经无力处理更多请求。另一个指标是 await,它代表每个 IO 请求的平均等待时间。如果 await 明显升高,例如 SSD 超过 10ms、HDD 超过 50ms,就说明磁盘在处理请求时出现了拥堵。而若 svctm(服务时间)也同步升高,则意味着磁盘本身速度变慢,可能与老化或坏块相关。如果 await 很高而 svctm 很低,则通常表示排队过多,是进程层面压力过大造成的等待。
在确认磁盘繁忙后,下一步必须找出具体是哪一个进程造成的压力。iotop 是定位元凶最直接的工具,可以实时查看每个进程的读写量:
iotop -oPa
结合输出内容,若某个 Java 进程频繁写入日志、某个 MySQL 实例的写磁盘量异常、rsync 正在执行大量文件同步、或某个程序陷入死循环不断读写临时文件,通常都能一眼看出。在某些情况下,可能不是单一进程,而是多个轻量级服务的 IO 聚合效应,这时需要综合判断总写入量与单进程行为。
如果未发现异常进程,但 IO 始终很高,应当检查系统是否因内存不足而大量使用 swap。频繁触发 swap 会导致磁盘作为“伪内存”频繁读写,严重拖累系统。使用以下命令:
free -m
vmstat 1 5
若发现 swap used 持续增加并伴随 si/so 数值不断波动,就说明内存已经不够并且系统正在频繁进行交换操作。此时需要优化应用内存占用、增加物理内存,或将 swappiness 调低,例如:
sysctl -w vm.swappiness=10
接下来,需要检查磁盘是否存在硬件层面的问题。系统日志是诊断硬盘异常的核心途径之一,通过以下命令检查是否有 I/O error 相关信息:
dmesg | grep -i error
dmesg | grep -i fail
一旦出现 I/O error、bad block 或 Buffer I/O error on device 等字样,说明磁盘设备存在物理问题,需要进一步使用 SMART 工具检测:
smartctl -a /dev/sda
如果 SMART 指标中 Reallocated_Sector_Ct 或 Pending_Sector_Ct 持续增长,磁盘已经开始出现坏块,应立即备份并更换设备。如果是云服务器,一般需要及时申请磁盘迁移或联系服务商处理。
对于 IO 异常但磁盘健康正常的情况,可以进一步排查具体的文件或目录是否存在暴涨行为。使用 du 查找增长速度最快的目录:
du -sh /* 2>/dev/null
常见的 IO 高负载来源包括应用日志目录、数据库 binlog、系统日志目录等。特别是 /var/log/messages、Nginx 访问日志、后台业务的调试连续输出往往是造成磁盘持续写入的核心来源。如果发现某个日志文件增长速度特别快,则需要检查应用是否存在异常打印或错误循环。
如果服务器运行 MySQL 或 PostgreSQL,此类数据库系统也可能在高负载情况下产生大量磁盘 IO。比如 MySQL 在未优化 SQL 时可能频繁做全表扫描,或因事务过大导致频繁 flush。在 MySQL 内部排查时常用:
SHOW ENGINE INNODB STATUS\G;
其中如果看到大量 pending writes、频繁 flush、redo log 写入量异常增大,说明负载已经超过当前磁盘能力。此时需要从数据层面优化索引、拆分大事务、调整 innodb_buffer_pool_size 或优化 binlog 刷盘策略,例如将 sync_binlog=1 在不影响一致性的前提下适当调高为 100。
除应用和数据库外,还需排查服务器上是否存在大规模备份、文件压缩、归档或同步任务,例如通过 crontab 触发的定时任务:
crontab -l
备份任务(如 tar、zip)、归档日志(logrotate)、rsync 文件同步都可能在执行期间占用大量 IO。如果这些任务运行无节制,常常导致磁盘在一段时间内完全占满。对同步类任务,可以加入限速参数,例如:
rsync --bwlimit=5000
或使用 ionice 降低后台任务优先级:
ionice -c3 tar -czf backup.tar.gz /data
排查完所有软件因素后,应回到系统层面进行必要的优化。例如调整 IO 调度器以适配 SSD:
echo none > /sys/block/sda/queue/scheduler
对于日志密集写入的应用,应通过 logrotate 定期分割日志并减少过度的 debug 输出。对于数据库,应提升内存缓存比例,减少不必要的磁盘访问。对需要大量 IO 的业务,应考虑将系统盘与数据盘分离,甚至部署 RAID10 或升级到 NVMe 高性能 SSD。
最终,将排查过程总结为一条完整且可复用的链路,可以避免日后重复定位问题。一般顺序如下:先从 top 判断是否为 IO 假死,再从 iostat 分析磁盘是否打满,然后通过 iotop 找到具体进程;接着判断是否是 swap 引起,并检查日志、数据库、大任务写入等常规因素;最后检查磁盘健康并根据实际情况进行优化或更换硬件。通过这一完整流程,大多数磁盘 IO 占满的问题都能迅速找到根因并有效处理。
推荐文章
