← [ BACK_TO_NOTES ]

Linux 磁盘占用检查与分析

从 filesystem、inode、目录、Docker、deleted-open file 到长期监控,建立一套从发现磁盘异常到定位业务 owner 的分层排查流程。

#howto #growing #ops #linux #linux

[!info] related notes

Linux 磁盘占用检查与分析

核心思路

不要从:

磁盘满了
→ 找几个看起来大的目录
→ rm -rf

开始。

应该分层回答:

1. 哪个 filesystem 满?
2. 是 block 还是 inode?
3. 哪个目录 / 文件占空间?
4. 它属于什么业务对象?
5. 是文件、数据库、容器 layer、cache,还是 deleted-open file?
6. 哪些空间真的可回收?
7. 为什么之前没有发现增长?

一张流程图

duf / df -hT
      │
      ├─ block usage 高
      │      ↓
      │   gdu -x --no-delete /
      │      ↓
      │   找到大目录 / 大文件
      │      ├─ Docker/containerd → docker system df / buildx du
      │      ├─ DB               → DB 自身工具 / retention
      │      ├─ logs             → journal/logrotate/app
      │      ├─ cache            → owner 工具自己的 cache clean
      │      └─ 对不上 df        → lsof +L1
      │
      └─ inode usage 高
             ↓
          找海量小文件

第 1 层:确认 filesystem

系统自带:

df -hT

更适合人工阅读:

duf

必须同时看 inode:

df -ih
# 或
duf --inodes

判断

Use% 高       → block capacity 问题
IUse% 高      → inode / 小文件数量问题
两者都正常    → 可能看错挂载点或业务告警口径

第 2 层:下钻目录

推荐:

sudo gdu -x --no-delete /

其中:

  • -x 避免跨 NFS / SSHFS / FUSE 等其他文件系统;
  • --no-delete 把分析与变更分离。

系统自带方案:

sudo du -xhd1 / | sort -h
sudo du -xhd1 /var | sort -h
sudo du -xhd1 /srv | sort -h

不断缩小范围:

/
→ /srv
→ /srv/app
→ /srv/app/data
→ 具体 DB / log / cache

第 3 层:找单个大文件

例如找大于 1 GiB 的文件:

sudo find / -xdev -type f -size +1G -printf '%s\t%p\n' \
  | sort -nr \
  | awk -F'\t' '{printf "%.2f GiB\t%s\n",$1/1073741824,$2}'

这一步很适合发现:

SQLite DB
日志
备份包
core dump
模型文件
临时归档

第 4 层:Docker / containerd 单独分析

如果大目录是:

/var/lib/docker
/var/lib/containerd

先运行:

docker system df
docker system df -v
docker builder du
docker buildx du

核心原则:

不要直接删除 /var/lib/docker 或 /var/lib/containerd 内部文件。

正确做法见 Docker 磁盘占用诊断。

第 5 层:df 与 du 对不上

先怀疑 deleted-open file:

sudo lsof +L1

典型模型:

app.log 20G
→ rm app.log
→ 应用仍持有 FD
→ 路径消失
→ 20G 数据块还在

此时 du 看不到,但 df 仍然计算这些 block。

详见 lsof +L1。

第 6 层:应用数据要按 owner 清理

看到大目录后,必须先分类:

类型例子正确动作
Cachenpm / pnpm / uv / Playwright用工具自己的 cache clean / 重建策略
DatabaseSQLite / PostgreSQL / app DB先分析表、retention、VACUUM/归档策略
Logsjournald / app logretention / rotate / reopen
Dockerimage / cache / volumeDocker CLI 判断引用
Backupsnapshot / tarball保留策略 + 明确删除旧版本
Sourcerepo / worktree / node_modules判断能否重建、是否仍在开发

不能因为“它大”就默认“它是垃圾”。

第 7 层:长期监控

现场排障回答:

现在空间去哪了?

长期监控回答:

从什么时候开始增长?增长速度是多少?哪台机器快到阈值?

轻量多节点:

更高粒度实时观测:

一个合理组合:

Beszel / Netdata
→ 发现 70% → 80% → 90% 的趋势

SSH
→ duf
→ gdu
→ Docker / DB / lsof
→ 根因

常见误区

误区 1:df 就能找出大目录

df 看 filesystem,不看目录树。

误区 2:du 最大的目录一定能删

它可能是数据库、volume 或生产数据。

误区 3:Docker image 显示的 SIZE 可以直接相加

layer 会共享,应看 Docker 自己的 usage / reclaimable 口径。

误区 4:磁盘没满就不用看 inode

百万级小文件可能先耗尽 inode。

误区 5:rm 一个大日志就一定释放空间

如果进程仍持有 FD,数据块不会立刻释放。

误区 6:生产服务器直接 gdu 里按 d

诊断工具和删除动作应分离。推荐 --no-delete。

快速 Checklist

# 1. 文件系统
[df / duf]
df -hT
df -ih
duf

# 2. 目录
sudo gdu -x --no-delete /

# 3. 大文件
sudo find / -xdev -type f -size +1G -printf '%s\t%p\n' | sort -nr | head

# 4. Docker
docker system df
docker system df -v
docker builder du
docker buildx du

# 5. deleted-open file
sudo lsof +L1

# 6. 日志
journalctl --disk-usage

# 7. 挂载关系
findmnt
lsblk -f

Oracle2 实战案例(2026-09-30)

一次真实排查中:

根盘 145G
清理前约 98%
清理后约 76%

继续下钻得到:

/var                 ~39G
  /var/lib/containerd ~35G

/srv                 ~28G
  hermes-personal     ~28G

/home                ~28G

随后在 Hermes Personal 中发现:

profiles/memoflow                    ~16G
state-snapshots                       ~4.1G
opencode/opencode.db                  ~9.1G

这个案例说明:

第一轮 Docker 清理解决“可回收垃圾”,第二轮仍必须回到业务数据生命周期本身。

掌握标准

  • 能区分 filesystem、directory、file、inode 四个层级。
  • 能解释 df 与 du 不一致的常见原因。
  • 能用 -x 避免跨文件系统误扫。
  • 能区分 Docker image、container、volume、builder cache。
  • 不直接删除 containerd 内部数据。
  • 能把“找到大文件”继续追到业务 owner 与 retention policy。
  • 能用长期监控在磁盘接近 100% 前发现趋势。
创建于 2026/9/29 更新于 2026/9/29
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本