磁盘还有空间却写不进去:inode 耗尽与已删除大文件的排查顺序
先分清两种「没空间」
看到 No space left on device,第一反应通常是磁盘满了。但 Linux 上文件系统有两类资源:数据块(block)和索引节点(inode)。任何一类用尽,写入都会失败,而报错信息完全一样。所以第一步不是删文件,而是分别确认这两类资源的状态:
df -h /var
# Filesystem Size Used Avail Use% Mounted on
# /dev/vda1 40G 18G 22G 45% /
df -i /var
# Filesystem Inodes IUsed IFree IUse% Mounted on
# /dev/vda1 2621440 2621440 0 100% /
上面这个例子很典型:block 只用了 45%,但 inode 已经 100%。此时无论怎么清理大文件都没用,因为缺的是「文件条目的名额」,不是存储空间。
一、inode 耗尽:先找小文件扎堆的目录
inode 数量在格式化时就固定了,每个文件、目录、符号链接都至少占一个。耗尽 inode 的从来不是大文件,而是数量巨大的小文件,常见来源有:
- 应用把每个请求写成一个小日志或临时文件,且从不清理;
- PHP/Python 的 session 文件、缓存碎片堆在同一个目录;
- 邮件队列、监控采集数据按秒落盘;
- 容器层里反复构建留下的中间文件。
按目录统计文件数量,从根往下逐层缩小范围:
for d in /var/*; do
printf '%8s %s\n' "$(find "$d" -xdev -type f 2>/dev/null | wc -l)" "$d"
done | sort -rn | head -20
找到数量异常的目录后,先确认这些文件是否还在被使用,再按修改时间清理,例如只删除 7 天前的缓存:
find /var/cache/app -xdev -type f -mtime +7 -delete
如果单个目录里就有几百万个文件,rm 会非常慢,而且可能再次把 inode 占满。更稳妥的做法是先停掉写入方,用 rsync -a --delete 同步一个空目录过去,或者直接重建目录。清理完成后用 df -i 确认 IUse% 是否降下来。
二、文件已删除,但空间没回来
另一种情况是 df 显示快满了,du 却怎么也对不上。原因通常是某个进程还持有已删除文件的句柄:文件在目录里已经看不见,但数据块要等进程关闭句柄才会释放。用 lsof 找 deleted 标记:
lsof +L1 2>/dev/null | sort -k7 -rn | head
# COMMAND PID USER FD TYPE DEVICE SIZE/OFF NLINK NODE NAME
# python3 18422 root 3w REG 253,1 12G 0 131074 /var/log/app.log (deleted)
处理方式取决于进程:能重载就重载(例如 systemctl reload 或 kill -HUP),不能重载就只能重启。日志类文件还有一个更温和的办法:清空而不是删除,让写入方继续用同一个 inode:
truncate -s 0 /var/log/app.log
这样既释放了空间,也不会因为 inode 被替换导致进程继续往「看不见的文件」里写。
三、确认是不是文件系统或配额问题
如果 block 和 inode 都不是 100%,还要看两个地方。一是挂载点是否写满,比如 /var/lib/docker 单独挂了一块小盘,根分区正常但容器写不进去;二是是否启用了磁盘配额:
findmnt -T /var/lib/docker
repquota -a 2>/dev/null | head
容器环境还要注意 overlay 层:镜像层是只读的,写入都落在可写层,docker system df 看到的占用和宿主机 df 往往不是一回事。
四、把监控补上,别等报错才发现
inode 使用率应该和磁盘使用率一起监控。很多监控模板只采集 df -h,漏掉了 df -i,结果就是空间看着很健康,服务却突然写不进日志。最简单的做法是在现有巡检脚本里加一行判断:
df -i --output=pcent /var | tail -1 | tr -dc '0-9'
超过 80% 就告警。另外给临时目录和缓存目录设置定期清理,日志统一走 logrotate,能避免绝大多数 inode 耗尽问题。
小结
遇到「还有空间却写不进去」,按这个顺序走:先 df -h 和 df -i 分清是 block 还是 inode;inode 满就找小文件扎堆的目录;空间对不上就用 lsof +L1 找已删除但仍被占用的文件。真正要长期解决的,还是把 inode 使用率纳入监控,并给缓存和日志设定明确的清理策略。
- 点赞
- 收藏
- 关注作者
评论(0)