磁盘还有空间却写不进去:Linux 排查的六个顺序

举报
yd_284037603 发表于 2026/11/06 20:47:18 2026/11/06
【摘要】 先说在前面线上最常见的报警不是「磁盘满了」,而是「磁盘明明还有 30G 却报 No space left on device」。这类问题不是磁盘坏了,而是看到的数字和实际限制不是一回事:df 看的是文件系统块,du 看的是目录占用,而写入还会受 inode、配额、已删除文件、挂载点遮挡等好几层约束影响。下面按排查顺序排一下,从最快能确认的开始。 1. 先分清 df 和 du 为什么对不上d...

先说在前面

线上最常见的报警不是「磁盘满了」,而是「磁盘明明还有 30G 却报 No space left on device」。这类问题不是磁盘坏了,而是看到的数字和实际限制不是一回事:df 看的是文件系统块,du 看的是目录占用,而写入还会受 inode、配额、已删除文件、挂载点遮挡等好几层约束影响。下面按排查顺序排一下,从最快能确认的开始。

1. 先分清 df 和 du 为什么对不上

df -h 读的是文件系统的超级块统计,du -sh 是遍历目录累加文件大小。两者差得离谱时,八成不是「算错了」,而是文件还占着空间、但目录里已经找不到它了(见第 3 条)。另外 du 统计的是块分配,大量小文件会让它和「逻辑大小」差不少。

df -hT                      # 先看是哪个文件系统、什么类型
du -sh /var/* 2>/dev/null | sort -h | tail -20
du -x --max-depth=1 /       # -x 不跨文件系统,避免把挂载点算进来

加 -x 这一步很关键:不加的话 du / 会顺着挂载点跑到数据盘甚至 NFS 上,得出的结论完全不可信。

2. df 没满,但 inode 用完了

每个文件至少占一个 inode,几十万个小文件(缓存碎片、session 文件、邮件队列、容器镜像层)就能把 inode 耗光,此时 df -h 显示还有空间,写入照样失败。

df -i                       # IUse% 到 100% 就是它
for d in /var /tmp /home; do echo "$d $(find $d -xdev -type f | wc -l)"; done

找到目录后别急着 rm -rf,先确认这些小文件的产生者,否则清完几小时又会满一遍。真要批量删,用 find ... -mtime +7 -delete 比 rm -rf * 安全得多——后者在文件数太多时会直接报参数列表过长。

3. 文件删了,空间没回来

这是「df 说满、du 说没占」最典型的原因:进程还开着某个文件的句柄,此时 rm 只是解除了目录引用,磁盘块要等最后一个句柄关闭才释放。日志文件被轮转后忘记让服务重新打开,就会撞上这个。

lsof +L1                    # 列出所有链接数为 0 但被占用的文件
lsof | grep deleted
# 稳妥做法:截断而不是重启服务
: > /proc/<pid>/fd/<fd>

logrotate 配 copytruncate 或在 postrotate 里给进程发 USR1/HUP,就是为了避开这个坑。生产环境别一上来就重启服务,先截断再排期重启。

4. 挂载点把原有文件盖住了

某个目录里本来堆了几十 G 数据,后来把新盘挂到了同一个路径,老数据没删也看不见,空间却一直被占着。du 默认会跟着新挂载点走,所以怎么算都对不上。

findmnt -o TARGET,SOURCE,FSTYPE,SIZE,USED
mount | grep ' /data '

确认是遮挡后,可以用 mount --bind / /mnt/root 从另一个视角看被遮住的原始目录,处理完记得 umount /mnt/root。这种问题在临时盘改挂永久盘时特别常见。

5. 容器场景:日志和 overlay2

Docker 默认的 json-file 日志驱动没有大小上限,一个刷异常日志的容器几天就能吃满 /var/lib/docker。另外 docker system df 和宿主机 df 统计口径不同,镜像层、悬空卷都要单独看。

docker system df -v
du -sh /var/lib/docker/containers/*/*-json.log | sort -h | tail
# daemon.json 全局限制,改后需重启 docker,新建容器才生效
{ "log-driver": "json-file", "log-opts": { "max-size": "100m", "max-file": "3" } }

清理顺序建议:先 docker system prune 清悬空对象,再单独确认匿名卷;prune -a 会删掉所有未被使用的镜像,生产机上要慎用。

6. 配额和保留块

ext4 默认给 root 保留 5% 的块,普通用户写到 95% 就会收到「无空间」,但 df 看着还有余量。云主机上还可能有项目配额、目录配额:

tune2fs -l /dev/vda1 | grep -i 'reserved block'
repquota -a                 # 用户/组配额
xfs_quota -x -c 'report -h' /data     # XFS 用这条

数据盘确认不需要 root 保留时,tune2fs -m 1 /dev/vdb1 能立刻腾出几个百分点;系统盘别乱改,那是给日志和救援留的。

小结:一条能直接照着跑的顺序

df -hT 定位文件系统 → df -i 排除 inode → du -x --max-depth=1 找大目录 → lsof +L1 查已删未释放 → findmnt 排除挂载遮挡 → 容器机再看 docker system df -v 和日志大小 → 最后查配额与保留块。按这个顺序走,绝大多数「还有空间却写不进去」都能在五分钟内定位,不用一上来就扩容——扩容解决不了 inode 用尽,也解决不了被占用的句柄。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。