磁盘写满会导致事务在fsync阶段完全停摆,insert/update/commit全部阻塞或报error 1030;需用df -h查mysql数据目录挂载点使用率≥95%、lsof查deleted文件、mysqladmin ping验证进程存活,并区分可删日志与必须停库处理的redo/binlog文件。

磁盘写满时事务会卡在 fsync 阶段,根本不会真正提交——不是慢,是停摆。此时 INSERT、UPDATE、COMMIT 全部阻塞或报 ERROR 1030 (HY000): Got error 28 from storage engine,连 SHOW PROCESSLIST 都可能卡住。设置预留空间告警不是“锦上添花”,而是防止服务雪崩的底线动作。
怎么确认磁盘满是主因而非其他故障
别一上来就删日志。先快速验证是否真被磁盘堵死:
- 用
df -h看 MySQL 数据目录挂载点(通常是/var/lib/mysql所在分区)是否Use%≥ 95% - 执行
lsof -p $(pgrep mysqld) | grep deleted:如果看到大文件名带(deleted),说明进程还在写一个已被 rm 的文件(比如误删了slow_query_log_file),空间没释放,必须kill对应线程 - 尝试
mysqladmin -u root -p ping:能通说明 mysqld 进程活着,问题在 IO 层;不通再查进程是否存在
哪些日志能立刻删、哪些必须停库
删错文件会导致 MySQL 启动失败。区分清楚再动手:
- 安全可删(无需停库):
slow_query_log_file、general_log_file—— 但得先关开关:SET GLOBAL slow_query_log = OFF;,否则删完立刻重建 - 必须停库后删:
ib_logfile0、ib_logfile1(redo log)、mysql-bin.*(binlog)—— 后者若主从依赖或需 PITR,改用PURGE BINARY LOGS BEFORE '2026-05-01 00:00:00'; - 不能删只能轮转:
error_log,用mysqladmin -u root -p flush-logs触发重命名,旧文件保留但停止写入
如何设磁盘预留空间告警(Linux + Prometheus)
靠人工巡检来不及。真实生产环境必须自动化盯盘:
- 监控项不是看
/,而是盯 MySQL datadir 所在挂载点,比如/var/lib/mysql→ 对应node_filesystem_avail_bytes{mountpoint="/var/lib/mysql"} - 告警阈值建议设为
10GB或5%(取更严者),因为innodb_log_file_size≥ 1G 时,一次 checkpoint 可能瞬时写几百 MB - 避免误报:加静默期(
for: 10m),排除短时 spike;同时叠加rate(node_disk_io_time_seconds_total[5m])看 IO 延迟是否同步飙升,交叉验证
为什么 innodb_file_per_table=OFF 下删表不释放空间
这不是 bug,是设计行为:ibdata1 是共享表空间,所有表数据、索引、undo log 全挤在里面。删表只是标记空间为“可复用”,但文件尺寸不缩。你看到 df 没变化,是因为:
-
OPTIMIZE TABLE在共享模式下无效 -
TRUNCATE TABLE仍会让ibdata1增长(尤其有大 BLOB) - 唯一回收路径是导出 + 停库 + 删
ibdata1+ 改配置 + 重建 —— 这个过程必须离线,且innodb_fast_shutdown要设为0,否则恢复时可能损坏
最易被忽略的一点:即使上了 NVMe,如果应用高频提交小事务,innodb_log_buffer_size 太小(默认 16MB)会导致 log buffer 频繁刷盘,fsync 成瓶颈。这时光清日志没用,得调大 buffer 或合并事务。











