技术指南

Linux 磁盘满排障:区分块、inode 与删除未释放

从失败路径出发,区分数据块、inode、删除未释放、journal、容器层与只读故障,再做最小范围恢复。

应用报 `No space left on device` 时,先定位失败路径所在的文件系统,再区分数据块、inode、删除后仍被进程占用的文件,以及只读或配额边界。`df` 与 `du` 回答的问题不同:前者报告文件系统可用空间,后者遍历仍可通过目录名访问的文件。两者不一致是线索,不是让其中一个结果“作废”。

先判断是哪一种耗尽

观察优先假设下一步
`df -h` 的 Use% 接近 100%,`df -i` 正常数据块不足在同一文件系统内比较目录、日志、容器和大文件
`df -i` 的 IUse% 接近 100%inode 不足,常见于大量小文件按目录统计文件数量并寻找持续生成者
`df` 很高但 `du` 合计明显偏低删除后仍打开的文件、被新挂载遮住的旧目录、快照或文件系统保留空间检查打开的低链接计数文件和挂载关系,不要反复删除可见文件
挂载选项出现 `ro`,或内核日志有 I/O/文件系统错误存储或文件系统故障,不是普通容量清理停止非必要写入,保全日志并进入磁盘/文件系统恢复流程
只有一个用户、项目或容器失败,整体仍有空间配额或隔离边界核对该用户、项目、容器或云卷的限制

锁定失败路径所在的文件系统

把 path 换成真实失败路径;先阅读完整输出,确认 TARGET 与 SOURCE 后再调查。时间窗应按真实事故调整
path=/var/lib/example
stamp=$(date --utc --iso-8601=seconds)
printf 'incident_utc=%s\npath=%s\n' "$stamp" "$path"
findmnt --target "$path" -o TARGET,SOURCE,FSTYPE,OPTIONS
df -hT "$path"
df -i "$path"
systemctl --failed --no-pager
journalctl -k --since '-30 min' --no-pager

给 `df` 一个文件或目录参数,会报告包含该路径的已挂载文件系统;`findmnt --target` 会把路径解析到相应挂载点。不要只看整机根分区:数据库、容器数据目录、临时目录和用户目录可能位于不同的卷,也可能被 bind mount 或网络文件系统覆盖。

在同一挂载点内找出可见占用

先把 mount 改为 findmnt 返回的挂载点。目录名和文件名可能包含敏感信息;大目录遍历会产生 I/O,繁忙主机应降低频率并避免并行重复扫描
mount=/var
sudo du -x --max-depth=1 --block-size=1 "$mount" | sort -n
sudo find "$mount" -xdev -type f -size +1G \
  -printf '%s\t%p\n' | sort -n

`du -x` 只遍历起点所在的文件系统,适合防止调查跨进另一个挂载卷。结果仍只是通过当前目录树可见内容的估计:写时复制、压缩、快照、稀疏文件和硬链接都会改变“文件大小”与“底层占用”的关系。先从最大的一层向下收敛,不要从根目录启动多个全盘扫描。

解释 df 与 du 的缺口

`+L1` 选择链接计数小于 1 的打开文件;需要足够权限才能看到其他用户进程。先记录 COMMAND、PID、FD、SIZE/OFF 和 NAME,不要直接改写 /proc/<pid>/fd
sudo lsof +L1
findmnt --target /var -o TARGET,SOURCE,FSTYPE,OPTIONS

文件名从目录中删除后,已有文件描述符仍可继续引用该文件,因此占用可能直到持有进程关闭描述符或安全重启才释放。先确认进程属于哪个 unit、日志是否仍需保留、服务能否有序重启。另一个常见缺口是目录原有内容被后来的挂载覆盖;应在维护窗口从救援环境或临时只读视图核对,不能在生产挂载点下盲目移动文件。

inode 满时找文件 churn,而不是找大文件

GNU du 的 --inodes 用于统计目录树中的 inode 数;在其他实现或旧版本上先查看 du --help。限定层级,确认热点后再向下一层调查
mount=/var
df -i "$mount"
sudo du -x --inodes --max-depth=2 "$mount" | sort -n | tail -n 40

inode 告急通常来自大量会话、队列、缓存、临时文件或碎片化小对象。找到目录后先识别写入服务和保留规则;删除 socket、锁文件、邮件队列、包管理数据库或应用 spool 可能破坏一致性。永久修复应限制生成速率、批量归档或采用服务支持的清理接口,而不是依赖周期性通配符删除。

把 systemd journal 从证据变成受控保留

这些命令用于盘点当前占用、可用启动记录和合并后的配置,不删除日志
journalctl --disk-usage
journalctl --list-boots
systemd-analyze cat-config systemd/journald.conf

确认 journal 是主要占用并已导出事故证据后,才考虑 `journalctl --rotate --vacuum-size=1G` 这类有损动作,并按实际保留需求选择数值。上游语义是:vacuum 只删除最旧的归档 journal;和 `--rotate` 同时使用会先把当前活动文件归档,因此能纳入清理。长期应通过 `SystemMaxUse=` 与 `SystemKeepFree=` 设置容量预算,并验收日志仍覆盖所需调查窗口。

容器主机先盘点对象和日志驱动

这些命令只盘点 Docker 管理的对象、容器可写层和默认日志驱动;卷内应用数据、bind mount 与外部日志仍需按其真实挂载点调查
docker system df -v
docker ps -a --size
docker info --format '{{.LoggingDriver}}'

Docker 的 `system prune` 会同时移除未使用的容器、网络、镜像和构建缓存;`--all` 扩大到所有未使用镜像,`--volumes` 还会处理匿名卷。因此它不是通用的“清日志”命令。先映射对象所有者,再使用对象类型对应的受控删除或保留策略。Docker 当前文档也提示默认 `json-file` 驱动不会自动轮转;改变 daemon 默认值只影响之后新建的容器,既有容器需要按部署流程重建才能采用新配置。

按根因释放最小必要空间

根因恢复动作必须保留的边界
删除后仍打开的大文件导出必要日志后有序重启持有它的单个服务确认 PID 与 unit,避免整机重启掩盖其他原因
单个日志或 journal 无界增长执行该服务支持的轮转/保留,再修正配置保留事故时间窗和远端采集完整性
容器可写层、镜像或构建缓存确认所有者后按对象类型定向回收不要误删停止容器、回滚镜像或卷数据
inode churn暂停生成者,按业务状态和年龄分批归档或删除队列、锁、socket 与事务文件必须用服务语义处理
只读挂载或 I/O 错误停止写入并按文件系统、磁盘或云卷流程恢复容量清理不能修复介质或文件系统损坏

用同一路径完成验收

仅在确认路径允许临时文件、权限和应用语义后执行写入检查;数据库数据目录等受控路径应改用应用自身的健康检查
path=/var/lib/example
findmnt --target "$path" -o TARGET,SOURCE,FSTYPE,OPTIONS
df -B1 "$path"
df -i "$path"
testfile="$path/.vpscope-write-check.$"
printf 'write-check\n' | sudo tee "$testfile" >/dev/null \
  && sudo rm "$testfile"
systemctl --failed --no-pager
  • 记录释放前后的字节、inode、挂载选项和真实业务错误率;目标是恢复必要余量,不是把使用率清到任意固定数字。
  • 确认写入者、日志采集、备份、数据库和容器仍健康,且删除或重启没有造成新的数据缺口。
  • 观察至少一个真实业务周期,确认空间和 inode 增长速率已经收敛;若仍增长,继续修复生成机制而不是扩大清理范围。
  • 清理通常不可回滚。保留变更前配置、对象清单和备份位置;误删后停止继续写入,按服务恢复流程或备份恢复。

同时管理容量、inode 与增长率

为每个关键文件系统分别监控可用字节、可用 inode 和增长率,并把挂载只读、I/O 错误、journal 占用、容器日志策略和备份成功纳入同一运维视图。阈值应来自写入峰值、日志保留、备份窗口和扩容提前量;单一的全机使用率无法覆盖小卷、inode churn 或配额故障。

本文命令在 2026-08-18 按 GNU Coreutils、util-linux、lsof、systemd 与 Docker 当前上游文档完成语义和语法审阅,没有在读者的 VPS 或生产文件系统上执行。发行版版本、文件系统、配额、快照、容器运行时和云卷实现会改变可见字段与回收方式;执行有损动作前应查看本机帮助、供应商恢复文档和业务备份状态。

返回知识库