inode耗尽会导致“no space left on device”错误,即使df -h显示磁盘空间充足;根本原因是inode表满而非数据块用尽,小文件多的场景(如日志、容器镜像)易触发,应优先用df -i排查。

inode 耗尽会导致 touch、mkdir 突然失败,但磁盘明明还有空间
这是最典型的 inode 问题现象:No space left on device 错误出现在 df -h 显示磁盘使用率才 12% 的时候。根本原因不是块(block)用完了,而是 inode 表满了——每个文件/目录都要占一个 inode,小文件多的场景(比如日志、缓存、Git 仓库、容器镜像层)特别容易踩中。
实操建议:
- 用
df -i查看 inode 使用率,重点关注Use%列,而非df -h - 排查高 inode 占用目录:
find /path -xdev -type f | cut -d/ -f2 | sort | uniq -c | sort -n(按一级子目录统计文件数) - 临时释放:清理
/tmp、/var/log/journal或旧的.log.*文件;注意rm后需确保进程已关闭对应文件描述符,否则 inode 不会立即回收 - 新建文件系统时,若预知小文件极多(如邮件服务器),可用
mke2fs -i 2048(每 2048 字节分配一个 inode)调低 inode ratio,但会略微增加元数据开销
stat 和 ls -i 看到的 inode 号,在 ext4 和 XFS 下含义不同
同一个文件,ls -i 输出的数字是它在当前文件系统中的唯一标识,但这个“唯一性”依赖于文件系统类型实现。ext4 中 inode 号是线性分配的,重启后新文件可能复用旧号;XFS 则用 64 位“inode number + generation number”组合保证跨 mount 的全局唯一性——这对备份工具(如 rsync --inplace)、硬链接校验、或基于 inode 做去重的程序很关键。
实操建议:
- 不要用
ls -i结果做长期唯一标识,尤其跨 reboot 场景;改用stat -c "%d:%i" file获取设备号+inode号组合,更稳妥 - XFS 下
stat输出的Generation:字段变化,意味着该 inode 曾被复用(比如文件删了又重建),此时仅靠 inode 号无法区分新旧文件 - 硬链接共享同一 inode 号,但符号链接是独立 inode —— 用
ls -li对比能快速验证链接类型
删除大量小文件时,rm -rf 慢得反常,其实是 inode 遍历和回收瓶颈
删 100 万个空文件,rm -rf dir 可能卡住几十秒,而 find dir -delete 或 rsync -a --delete /empty/ dir/ 快得多。这不是命令本身的问题,而是 ext4 在 unlink 时要逐个更新 inode 位图、块位图、目录项,且默认不批量提交元数据。
实操建议:
- 避免在高 IO 压力下执行大范围
rm -rf;优先用find dir -mindepth 1 -delete,它边遍历边删,减少内存压力 - 对临时目录(如
/tmp),挂载时加noatime,nodiratime减少 inode 更新频率;极端场景可考虑mount -o remount,barrier=0(仅限数据可丢的测试环境) - XFS 用
xfs_fsr整理碎片后,大批量删除会略快;但真正治本是控制单目录文件数——Linux 目录性能在 >10k 条目后明显下降
docker build 或 CI 构建失败报 failed to create /xxx: No space left on device,大概率是 overlay2 下层 inode 耗尽
Docker 默认用 overlay2 存储驱动,每层镜像、每个构建中间步骤都会生成大量小文件(尤其是 npm install、pip install)。这些文件共用宿主机根文件系统的 inode,但 df -i 看不到容器层细节,容易误判。
实操建议:
- 查 overlay2 实际路径:
docker info | grep "Docker Root Dir",然后df -i /var/lib/docker - 清理无用构建缓存:
docker builder prune -af(Docker 23.0+)或docker system prune -af - 长期方案:把
/var/lib/docker单独挂载到一块 inode 充足的磁盘(如 1TB SSD 分配 200M inode),或改用zfs存储驱动(动态 inode 分配) - CI 脚本里加检查:
df -i /var/lib/docker | awk 'NR==2 {exit $5 > 90}' || echo "inode usage too high"
inode 不是抽象概念,它是实实在在的内存+磁盘结构,修改、删除、甚至 stat 一次都在触发它。小文件场景下,它的消耗速度远超直觉——别等报错才查 df -i。











