文章背景图

磁盘还有空间却提示 No space left on device:inode、删除未释放与配额排查

2026-08-08
10
- 字
- 分钟

“No space left on device” 不只代表磁盘字节用完。inode 耗尽、文件删除后仍被进程占用、用户配额、容器可写层、预留块、tmpfs 或挂载点异常,都可能产生同样报错。下面给出一套先定位对象、再安全释放、最后验证防复发的流程。

一、先确认报错对象和业务影响

记录报错时间、应用、完整路径、写入类型和最近变更。先判断是日志写不进去、数据库无法落盘、上传失败,还是节点级服务异常。涉及数据库时不要直接删除数据文件或日志文件。

date -Is
df -hT
df -i
findmnt -T /发生报错的路径
ls -ld /发生报错的路径
journalctl --since "30 min ago" -p warning

二、检查容量、inode 和真实挂载点

df -h 看块空间,df -i 看 inode。路径可能位于单独分区、bind mount、overlay 或 tmpfs,不能只看根分区。使用 findmnt -T 明确它实际属于哪个文件系统。

df -hT /目标路径
df -i /目标路径
findmnt -T /目标路径
stat -f /目标路径
mount | column -t

若 Use% 为 100%,继续找大目录;若 IUse% 为 100%,重点找海量小文件;两者都正常则转向“删除未释放”、配额和文件系统限制。

三、块空间耗尽:安全找出大户

du -xhd1 /目标挂载点 2>/dev/null | sort -h
du -xah /目标挂载点 2>/dev/null | sort -h | tail -50
find /目标挂载点 -xdev -type f -size +1G -printf '%s %p
' 2>/dev/null | sort -n | tail -30

-xdev 避免跨到其他文件系统。先从目标挂载点逐层下钻,避免对整机无边界扫描。日志应通过 logrotate 或应用接口轮转,不要直接删除仍在写入的文件。数据库、容器存储和包管理目录应使用各自清理机制。

四、inode 耗尽:定位海量小文件

for d in /目标挂载点/*; do printf '%s ' "$d"; find "$d" -xdev -printf '.' 2>/dev/null | wc -c; done | sort -k2 -n
find /目标目录 -xdev -type f | head
find /目标目录 -xdev -type f -printf '%h
' | sort | uniq -c | sort -n | tail -30

常见来源包括 session、缓存、邮件队列、临时文件、解压目录和异常日志切片。删除前确认保留策略与业务所有者;文件数量极大时应分批处理,避免一次性 rm 展开参数或造成 I/O 峰值。

五、文件已删除但空间没有释放

Linux 文件只要仍被进程打开,其数据块就不会释放。此时 df 很满,而 du 汇总明显偏小。

lsof +L1
lsof +L1 /目标挂载点
ls -l /proc/<PID>/fd | grep deleted

优先让应用重新打开日志,例如发送应用支持的 reopen 信号、执行安全 reload 或按变更流程重启服务。不要随意向 /proc/PID/fd 写空;这可能破坏应用状态。处理后再次确认 lsof +L1 和 df。

六、检查用户、组和项目配额

quota -s
repquota -a
mount | grep -E 'usrquota|grpquota|prjquota'
# XFS 项目配额示例
xfs_quota -x -c 'report -h' /目标挂载点

配额错误常表现为某个用户或项目无法写入,而其他用户正常。临时提高配额前需确认总容量、审批和回滚值;长期应调整保留策略或容量模型。

七、预留块、只读文件系统和文件系统错误

findmnt -no SOURCE,FSTYPE,OPTIONS -T /目标路径
dmesg -T | grep -Ei 'I/O error|read-only|ext4|xfs' | tail -100
# ext 文件系统只读查看预留信息
tune2fs -l /dev/正确设备 | grep -E 'Reserved block count|Block count|Reserved block percentage'

ext 文件系统会为特权用户预留部分空间,普通用户可能先收到 ENOSPC。不要在未确认设备和用途时修改预留比例。若文件系统变为只读或出现 I/O error,应优先保护数据、切流并按存储故障流程处理;不要在线盲目执行 fsck。

八、tmpfs、共享内存与临时目录

df -hT /tmp /run /dev/shm
findmnt -t tmpfs
ipcs -m
systemd-tmpfiles --clean --dry-run

tmpfs 消耗内存而非普通磁盘,容量或 inode 都可能单独耗尽。清理共享内存前必须确认所属进程。先使用 dry-run 检查 systemd 临时文件策略,不要对活动文件做批量删除。

九、容器与 Kubernetes 场景

docker system df -v
docker ps --size
kubectl describe node <NODE>
kubectl get events -A --sort-by=.lastTimestamp | grep -i -E 'disk|ephemeral|evict' | tail -30
kubectl describe pod <POD> -n <NS>

检查镜像、停止容器、构建缓存、容器日志和 writable layer。Kubernetes 还要关注 ephemeral-storage request/limit、imagefs、nodefs 和 DiskPressure。不要在生产节点直接执行无筛选的 docker system prune,它可能删除仍需用于快速回滚的镜像或缓存。

十、安全止血顺序

  1. 暂停产生数据的非核心任务,限制日志或上传增长。

  2. 按保留策略删除已确认可删的过期文件,并分批执行。

  3. 轮转或压缩日志;让持有 deleted 文件的进程安全 reopen。

  4. 必要时扩容文件系统,但先确认云盘、分区、LVM 和文件系统各层步骤。

  5. 数据库不可写时优先切流、扩容或使用产品自带清理流程。

十一、扩容后的分层验证

云盘变大不等于文件系统已经变大。需要依次确认块设备、分区、PV/LV 和文件系统。命令随布局不同,必须先只读识别,不能照抄设备名。

lsblk -f
pvs
vgs
lvs
df -hT /目标路径
# 完成获批的扩容步骤后再次核对
findmnt -T /目标路径

十二、恢复验证与监控

df -hT /目标路径
df -i /目标路径
lsof +L1 /目标挂载点
journalctl --since "10 min ago" -p warning

同时执行真实业务写入测试,确认数据库、日志、上传和监控恢复。至少观察一个增长周期,避免释放少量空间后很快再次耗尽。

十三、防复发

  • 容量和 inode 分别设置趋势告警,预留足够处置时间。

  • 日志统一轮转、压缩、保留和远端归档,并验证 reopen。

  • 临时文件、缓存、会话和任务输出都有上限与生命周期。

  • 监控 deleted-open 文件、容器可写层和 Kubernetes ephemeral storage。

  • 建立扩容、清理、切流和只读保护的标准操作手册。

十四、检查清单

  • □ 已确认真实路径、文件系统和故障范围

  • □ 块空间与 inode 已分别检查

  • □ 已排查 deleted-open、配额、tmpfs 和只读状态

  • □ 清理对象有保留策略,未误删数据库或活动文件

  • □ 扩容后已验证所有存储层和真实业务写入

  • □ 告警、轮转、配额和容量行动项已落地

总结

面对 ENOSPC,正确顺序是:找准写入路径和挂载点,区分块、inode、打开文件和配额,再做最小风险释放或扩容,最后用真实写入和趋势监控验证。

原创

磁盘还有空间却提示 No space left on device:inode、删除未释放与配额排查

本文链接: 磁盘还有空间却提示 No space left on device:inode、删除未释放与配额排查

本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。

评论交流

文章目录