服务器磁盘 IO 异常全场景总结
核心概念 磁盘 IO 异常通过 iostat/iotop/vmstat 等工具定位,覆盖 util 100%、iowait 高、IOPS 打满等典型场景。
1. 前置基础指标
核心观测命令:iostat、iotop、vmstat、sar -d
关键指标:
%iowait:CPU等待磁盘IO的时间占比(大于30%判定IO压力大)%util:磁盘设备繁忙度,接近100%代表磁盘打满瓶颈rMB/s、wMB/s读写带宽;r/s、w/s每秒读写IO次数(IOPS)avgqu-sz:IO请求平均队列长度,数值越大阻塞越严重await:单次IO平均等待耗时,正常<10ms,几十上百ms代表磁盘拥堵
2. 场景1:磁盘util持续100%,iowait高,业务大量超时阻塞
2.1. 现象
iostat -x 1磁盘%util=100%,%iowait长期40%~90%;- 业务接口缓慢、数据库查询超时、日志输出卡顿;
- shell命令、ls、cat文件执行延迟;
- 系统load average持续走高,但CPU idle空闲很多;
- Java应用频繁STW、大量线程阻塞在写文件。
2.2. 根因
- 高频随机读写(数据库MySQL/Redis、ES分片、Kafka),IOPS打满磁盘上限;
- 大量同步刷盘策略:MySQL sync_binlog=1、Redis AOF always、频繁flush;
- 海量日志同步落盘,应用疯狂打error堆栈日志;
- 定时任务扎堆:日志切割、数据库统计、全量备份、ES段合并;
- 机械硬盘HDD,随机读写性能极差,并发下极易跑满util。
2.3. 排查方案
- 定位占用IO最高进程
iotop -oP # 只展示有IO操作的进程,按读写排序
pidstat -d 1 # 按进程输出磁盘读写速度
- 查看磁盘读写指标,区分读瓶颈/写瓶颈
iostat -x 1
# r/s高=读瓶颈;w/s高=写瓶颈
- 定位进程读写哪些文件
lsof -p PID # 查看进程打开的文件句柄
cat /proc/PID/io # 进程累计读写字节
- 确认定时任务、中间件后台任务日志
grep -E "merge|backup|dump" /var/log/messages
crontab -l
2.4. 解决方案
- 硬件升级:HDD更换SSD/NVMe,大幅提升随机IOPS;
- 调整刷盘策略,减少同步落盘:
- MySQL:sync_binlog=1000,innodb_flush_log_at_trx_commit=2;
- Redis:AOF appendfsync everysec;
- 日志优化:关闭冗余堆栈日志,日志输出异步缓冲,日志落盘单独磁盘;
- 拆分定时任务,错峰执行,禁止凌晨同时备份+统计;
- 数据库分库分表、冷热数据分离,冷数据归档至低速存储。
3. 场景2:大量写IO,磁盘wMB/s、w/s极高,读压力很小
3.1. 现象
w/s、wMB/s数值暴涨,r/s很低,util接近100%;- 磁盘await持续升高,写入请求排队;
- 写入业务阻塞,读取业务基本不受影响。
3.2. 根因
- 消息队列Kafka/RocketMQ大量消息落地;
- 应用疯狂输出业务日志、异常堆栈;
- 数据库大批量insert、批量导入数据;
- 定时全量备份、数据reindex、文件同步rsync;
- 系统脏页积压,内核集中刷脏页产生写风暴。
3.3. 排查方案
iotop定位写IO大户;- 查看内核脏页占用:
cat /proc/meminfo | grep Dirty; - 查看应用日志输出速率、中间件日志磁盘占用增速。
3.4. 解决方案
- 日志分离:日志单独挂载高速磁盘,业务盘与日志盘物理隔离;
- 调整内核脏页参数,平缓刷盘,避免瞬间写风暴:
vm.dirty_background_ratio = 5
vm.dirty_ratio = 10
- 批量写入拆分批次,降低单次写入并发;
- Kafka调整log.flush策略,减少高频同步刷盘;
- 备份任务限流、错峰执行,避开业务高峰。
4. 场景3:大量读IO,r/s、rMB/s拉满,写入正常
4.1. 现象
磁盘读IO打满,查询类业务缓慢,写入无明显延迟。
4.2. 根因
- 数据库无索引全表扫描、频繁大分页查询;
- ES高基数聚合、海量日志检索;
- 定时报表全量读取历史数据;
- 程序频繁加载大文件、本地缓存失效反复读盘;
- 内存不足,大量文件无法缓存,频繁缺页中断读磁盘。
4.3. 排查方案
pidstat -d 1定位读IO进程;- 查看数据库慢查询日志,定位全表扫描SQL;
free -h查看可用内存、Cache占用。
4.4. 解决方案
- 数据库加索引,优化慢SQL,限制全表查询;
- 增加应用内存缓存(Redis本地缓存),热点数据常驻内存;
- ES冷热分离,冷数据冻结/归档,热数据放高速SSD;
- 增大服务器内存,提升PageCache缓存命中率。
5. 场景4:iowait高,但磁盘util不高,IO队列长
5.1. 现象
util 60%~80%,avgqu-sz 队列很长,await几十ms,单IO耗时久。
5.2. 根因
- 机械硬盘寻道慢,随机IO延迟高;
- 磁盘存在坏道,读写重试耗时;
- 存储远端NAS/云存储网络延迟高,远程IO往返耗时;
- 单磁盘多业务混跑,读写争抢资源。
5.3. 排查方案
- 磁盘健康检测:
smartctl -a /dev/sda查看坏块、重映射扇区; - 区分本地盘/远程NAS存储;
- iostat观察单块磁盘多业务读写并发。
5.4. 解决方案
- 更换SSD本地盘替代HDD/NAS;
- 磁盘故障则下线更换硬盘,数据迁移;
- 业务物理分盘,数据库、日志、程序分开挂载不同磁盘。
6. 场景5:脏页风暴,周期性瞬时IO尖峰
6.1. 现象
平时IO平稳,每隔一段时间瞬间util打满,业务短暂卡顿,周期性毛刺。
6.2. 根因
- 内核脏页达到阈值,后台一次性批量刷脏页;
- Redis RDB持久化、MySQL定时落盘、定时日志切割压缩;
- ES定时段合并、定时数据统计任务。
6.3. 排查方案
- 监控磁盘IO时序曲线,确认尖峰固定周期;
- 查看定时任务、中间件持久化日志;
- 监控
/proc/meminfoDirty脏页数值变化。
6.4. 解决方案
- 调小脏页后台比例,持续平缓刷盘,避免集中冲刷;
- 分散定时任务执行时间,错开持久化、备份、合并任务;
- 中间件持久化调整为增量、异步刷盘,减少全量落地。
7. 场景6:K8s容器IO受限,业务读写缓慢(cgroup限流)
7.1. 现象
节点磁盘util不高,但单个Pod内应用读写卡顿,报错IO阻塞。
7.2. 根因
- Pod配置
limits.readIOPS/limits.writeIOPS磁盘IO配额,触发内核限流; - 多个Pod共享一块磁盘,相互抢占IO资源;
- 容器日志输出过多占用磁盘IO,挤压业务读写。
7.3. 排查方案
- 进入Pod执行
iostat/iotop查看容器内IO; - 查看Pod资源yaml中的IO限额配置;
- 节点全局iotop定位容器对应进程。
7.4. 解决方案
- 根据业务提升Pod IOPS配额,高IO业务单独调度至独享磁盘节点;
- 日志sidecar异步采集,容器内关闭同步日志输出;
- 使用LocalPV本地SSD给数据库、ES等高IO应用。
8. 场景7:磁盘空间满 / inode耗尽引发IO卡死
8.1. 现象
- df查看磁盘100%占用,应用无法写入文件;
touch、日志输出、数据库落盘直接失败;- 若inode占满(大量小文件),df空间充足但无法新建文件。
8.2. 根因
日志未切割堆积、临时文件未清理、海量小文件未删除。
8.3. 排查方案
df -h # 磁盘空间
df -i # inode使用量
find /data -type f -size +1G # 查找大文件
8.4. 解决方案
- 配置logrotate自动切割清理过期日志;
- 定时清理临时缓存文件、过期备份;
- 海量小文件业务改用对象存储归档,定期删除无用碎片文件。
通用标准化排查流程
- 全局观测:
iostat -x 1确认磁盘util、iowait、读写IOPS,判断读/写瓶颈; - 定位进程:
iotop、pidstat -d 1找到消耗IO最高的PID; - 追踪文件:
lsof /proc/PID/io查看进程读写的文件/磁盘; - 区分诱因:业务日志/数据库/定时任务/内核脏页/磁盘硬件故障;
- 临时止损:暂停定时任务、清理大日志、限流批量写入;
- 长期优化:硬件升级、内核参数调优、业务架构拆分、缓存优化、分盘隔离。
关联文档