用受限 inode 的临时 tmpfs 复现“有空间却创建不了文件”,练习区分 inode 与容量问题

演练目标

环境准备

Linux 虚拟机或一次性特权容器,具备 root 和 mount。实验只挂载到 /tmp/lab-inode,不触碰宿主机已有文件系统。

sudo -i
mkdir -p /tmp/lab-inode
mount -t tmpfs -o size=64m,nr_inodes=256 tmpfs /tmp/lab-inode
findmnt -T /tmp/lab-inode
df -h /tmp/lab-inode
df -i /tmp/lab-inode

nr_inodes=256 是本次实验的关键参数。确认 df -i 的 Inodes 总数约为 256 后再继续。tmpfs 的 inode 限制只影响这个挂载点,删除挂载点后自动消失。

注入故障

创建大量空文件,直到 inode 用尽:

for i in $(seq 1 300); do
  : > "/tmp/lab-inode/file-$i" || { echo "failed at file-$i"; break; }
done

循环应在前 260 个文件左右报 No space left on device 并退出。此时每个文件几乎不占数据块,但都消耗一个 inode。

观察现象

df -h /tmp/lab-inode
df -i /tmp/lab-inode
find /tmp/lab-inode -maxdepth 1 -type f | wc -l
du --inodes -x --max-depth=1 /tmp/lab-inode | sort -n
touch /tmp/lab-inode/after-full

预期 df -h 仍显示大量可用空间,df -i 的 IUse% 为 100%,文件计数接近 inode 总数,新建文件继续报 No space left on device。

判断与定位

  1. 创建文件或写日志报 ENOSPC 时,同时看 df -h 和 df -i,不要只看容量。
  2. df -h 有余量、df -i 满,就是 inode 耗尽;两者都满才是容量耗尽。
  3. 用 du --inodes 找出小文件最多的目录,常见于缓存、session、队列和构建产物。
  4. 容易误判:df -h 有空间会让人怀疑应用权限或磁盘故障,实际是文件系统元数据耗尽。另一个误判是只删除大文件,但大文件释放的是数据块,不是被小文件占满的 inode。
  5. 目录本身也消耗 inode;海量空目录同样可能耗尽 inode。

修复

先确认这些文件可删除,再按范围清理:

find /tmp/lab-inode -maxdepth 1 -type f -name 'file-*' -delete
df -i /tmp/lab-inode
touch /tmp/lab-inode/after-full
ls -l /tmp/lab-inode/after-full

touch 成功即表示 inode 已释放。生产环境应优先处理产生海量小文件的程序,例如关闭按请求切分日志、调整缓存淘汰策略、把队列消息落到对象存储,而不是长期靠人工删除。

清理与回滚

umount /tmp/lab-inode
rmdir /tmp/lab-inode

如果 umount 报忙,先用 lsof +f -- /tmp/lab-inode 查找占用进程。tmpfs 卸载后内容全部消失,不会影响其他挂载点。

复盘

延伸阅读

读完自测

  1. df -h 有空间但创建文件报 ENOSPC,首先应该看哪个指标?
  2. 为什么删除几个大文件可能无法恢复文件创建?
  3. 生产环境如何降低 inode 再次耗尽的风险?
答案
  1. 先看 df -i,确认 inode 是否耗尽。
  2. 大文件主要占用数据块;inode 耗尽需要释放文件数量,删除大文件不一定减少足够的 inode 占用。
  3. 控制小文件产生源头,调整日志轮转和缓存策略,按小文件数量规划 inode,必要时使用 XFS 或独立文件系统。