Linux 磁盘满了怎么办:df、du 排查清单
“No space left on device”是运维里最常见的告警之一:网站写不进日志、数据库拒绝写入、连 crontab -e 都保存失败。磁盘满了别急着乱删,先定位“谁占的”,再决定“能不能删”。下面按顺序给出一份排查清单,命令在主流发行版上通用,个别参数以你所用系统的 man 手册为准。
第 1 步:用 df 看是哪个分区满了
df -h
-h 让大小以 K、M、G 显示。重点看 Use% 接近 100% 的那一行,以及它的挂载点(Mounted on)。很多服务器的 /、/var、/home 是不同分区,满的是哪个,就只在那个挂载点下找。注意 df -h 用的是 1024 进制,和硬盘厂商标的 GB 不一样,换算可以用 单位换算工具 里的 GB 与 GiB。
第 2 步:用 du 一层层找大目录
du -xh --max-depth=1 /var | sort -h
-x 表示只统计当前分区,不跨到别的挂载点;--max-depth=1 只列第一层;sort -h 能正确排序带单位的数字,最大的排在最后。找到最大的子目录后,把路径换成它再执行一次,逐层往下钻。常见的“大户”是 /var/log、/var/lib/docker、数据库目录、备份目录和用户上传目录。
想直接找大文件,可以用:
find /var -xdev -type f -size +500M -exec ls -lh {} \;
第 3 步:df 和 du 对不上?查“已删除但仍被占用”的文件
一个经典坑:明明删掉了几个 G 的日志,df 显示的空间却没有回来。原因是某个进程还打开着这个文件,文件名虽然没了,数据块要等进程关闭文件后才会释放。用下面的命令找出来:
lsof +L1
lsof | grep deleted
找到对应进程后,正确做法是让服务重新打开日志(很多服务支持 reload)或重启该服务。以后清空正在写入的日志,用 truncate -s 0 文件名 或 : > 文件名,不要直接 rm。
第 4 步:空间还有,却提示写不进?看 inode
df -i
每个文件都要占用一个 inode。如果某个目录里堆了几百万个小文件(会话文件、邮件队列、缓存碎片),inode 会先于空间耗尽,现象同样是 “No space left on device”。IUse% 到 100% 时,要找的是“文件数量最多的目录”,而不是最大的目录。
第 5 步:常见的清理对象
| 位置 | 处理方式 |
|---|---|
| systemd 日志 | journalctl --disk-usage 查看,journalctl --vacuum-size=500M 只保留最近 500M |
| /var/log 下的旧日志 | 确认 logrotate 正常工作,压缩包可按保留策略删除 |
| 软件包缓存 | Debian 系 apt-get clean,红帽系 dnf clean all |
| Docker | docker system df 查看,docker system prune 清理前务必看清提示,它会删除停止的容器和未使用的镜像 |
| 旧备份 | 先确认异地另有副本,再删本地过期文件 |
安全清理的三条原则
- 先看后删:删除前用
ls -lh确认路径,尤其是带通配符的命令,先把rm换成ls跑一遍。 - 不碰正在用的数据:数据库的数据文件、事务日志不能手动删,应使用数据库自己的清理或归档机制。
- 留出余量:清到刚好能用并不够,建议把使用率降到安全线以下,再处理根本原因。
治本:别让它再满一次
临时清理只解决当下。长期来看,要给日志配置轮转和保留天数,给备份脚本加上“只保留最近 N 份”的逻辑,并把磁盘使用率纳入监控。定时清理任务可以写成 cron,用 Cron 表达式解析器 核对执行时间;如果日志里记的是时间戳,排查“什么时候开始暴涨”时可用 时间戳转换 换成北京时间。日常巡检可参考 《IT 日常巡检清单》。
命令细节请以官方手册为准,例如 GNU coreutils 的 du 文档。