↓ 跳过正文

dust:快速定位磁盘空间究竟去了哪里

·4149 字·9 分钟·
目录
modern-cli - 这篇文章属于一个选集。
§ 12: 本文

阅读信息

  • 内容类型:教程
  • 难度:入门
  • 适合谁:希望在 Linux、WSL2 与远程服务器上提升命令行效率的开发者。
  • 读完后:用 dust 分析项目构建目录、日志目录与文件系统热点,并避免权限、挂载点和 WSL 跨盘扫描造成误判。
  • 依据版本:dust 1.2.5
  • 验证日期:2026-09-11

当服务器或本地开发机报出 No space left on device 时,df -h 只能告诉你“哪一个挂载点满了”,却无法展示空间究竟被埋在深层目录的哪个角落。

在传统 Linux 工作流中,排查磁盘热点往往需要繁琐地组合管道命令:

du -h --max-depth=1 /path | sort -hr | head -n 20

这种方式不仅打字成本高,且每次深入下一层子目录都要重新拼接命令,缺乏直观的全局比例感。dust 将目录大小计算与层级结构可视化融为一体,输出一棵带占用百分比与字符条形图的目录树,让大块空间分布一目了然。

df:确定哪个文件系统或挂载分区容量报警
dust:直观展示目标目录树内各层级子项的空间占用占比

需要明确的是:dust 仅负责只读分析与终端展示,不会自动删除任何文件。本文以 dust 1.2.5 为规范与本地实测版本。

从 df 确认满盘文件系统,用 dust 限制挂载范围并逐层定位 build、日志和大小口径问题,再核对清理条件
图:先限定文件系统并逐层锁定热点;确认路径、所有者、生成方式、可恢复性和官方入口后才清理。

1. 排查起点:先确认文件系统范围
#

绝不要在磁盘告警时盲目直接执行 dust /。根目录包含虚拟文件系统与外部挂载盘,全盘扫描会导致大量的无意义 I/O。

规范的第一步是使用 df 查看容量与挂载分区:

df -h
df -h /path/to/suspect

确认告警的是系统根分区(/)、独立数据盘(如 /data),还是 WSL2 中挂载的 Windows 分区(/mnt/c)。定位到大致目标后,再针对可疑顶层目录启动 dust:

dust /path/to/suspect

理解 dust 独特的默认展示方向
#

dust 在终端中输出的排版逻辑与常规命令有所不同:

  • 默认倒排(自底向上):dust 默认将总计行(100% 根目录)打印在终端输出的最底部,最大的子分支紧随其上,较小的项排在最上方。这样设计的目的是当扫描结果较长滚屏时,用户在终端光标停留的最底行能立刻看到最关键的总结与最大瓶颈。
  • 正向树形(-r, --reverse):如果你习惯像文件管理器那样从上往下阅读(总目录在最顶层,子项在下方展开),只需要加上 -r 参数。

在测试小型样本时,各分支的显示字节数由底层文件系统的最小分配单元(块大小)决定,读者应重点关注条形图比例与相对排位,而非跨机器比较微小的字节差异。

2. 核心参数:控制扫描深度与聚焦范围
#

面对数万个文件的庞大目录树,未经限制的输出很容易刷满终端缓冲区。掌握以下四个旋钮是高效定位的关键:

1. 限制条目数量(-n, --number-of-lines)
#

默认情况下,dust 会尝试填满当前终端窗口的高度。如果只想聚焦最突出的几个大项:

dust -n 15 /var

注意:-n 仅限制终端最终渲染输出的行数,并不代表 dust 内部只扫描了 15 个文件。为了找出究竟谁最大,工具仍然需要完整遍历目标路径。

2. 控制展示深度(-d, --depth)
#

在初次探查大型未知目录时,使用深度限制可以快速识别大分支,避免被深层碎片文件淹没:

dust -d 2 /var

一旦在第 2 层锁定了热点(例如发现 /var/log 占据了 80% 的体积),再进一步将热点作为新起点深入分析:

dust -d 3 /var/log

3. 限制在同一文件系统(-x, --limit-filesystem)
#

这是生产环境与根目录排查中最关键的安全参数:

dust -x -d 2 /

-x 会严格阻止 dust 跨越挂载点边界。它能确保扫描不会意外深入到:

  • 伪文件系统:/proc、/sys、/dev(这些不是真实磁盘占用);
  • 远程挂载:NFS、CIFS/Samba、SSHFS 网络存储;
  • 宿主机桥接:WSL2 中的 /mnt/c 或容器内挂载的外部卷。

4. 仅看目录或仅看文件
#

  • -D, --only-dir:输出中隐藏普通文件,只看各层级目录的聚合大小;
  • -F, --only-file:跳过目录聚合,直接按单个文件大小排序,迅速揪出误存的单个大 tar 包、iso 镜像或孤立核心转储(core dump)。

3. 场景一:定位项目工程构建产物的膨胀
#

在日常编码中,代码仓库经常会在几周内膨胀到数个 GiB。先从仓库根目录做全局纵览:

dust -n 25 -d 2 .

如果发现 build/、target/、.next/、node_modules/ 或编译缓存占据绝大多数空间,再单独对热点目录展开:

dust -d 3 target

规范清理准则
#

在确认空间被编译中间件占据后,切勿无脑直接执行 rm -rf:

  1. 优先使用构建系统内置的清理目标:
    # Rust 项目
    cargo clean
    # CMake 项目
    cmake --build build --target clean
    # Node.js 项目
    npm run clean
  2. 警惕误删开发数据:在很多团队中,开发者习惯临时将测试数据库(如 SQLite 文件)、本地密钥或未提交的测试样本随手扔在 build/ 或缓存子目录下。递归删除前,先核对路径中是否存在不可恢复的资产。

4. 场景二:排查日志与系统目录满溢
#

排查 /var/log 或 /var/lib 时,普通用户账号常会遇到读取权限限制:

dust -n 20 -d 2 /var/log

如果某些子目录权限为 0700,dust 会因无法进入而导致该分支统计不全。可以附加 --print-errors 查看哪些路径被跳过:

dust --print-errors -d 2 /var/log

典型热点与治理方式:
#

  1. Systemd Journal 日志过大: 如果发现 /var/log/journal/ 占用了几十个 GiB,不要直接执行 rm -rf,否则可能导致 journald 状态异常。使用其自带的轮转与修剪机制:
    # 查看当前 journal 真实占用
    journalctl --disk-usage
    # 仅保留最近 7 天的日志,或限制总体积在 2G 以内
    sudo journalctl --vacuum-time=7d
    sudo journalctl --vacuum-size=2G
  2. Docker / 容器存储层堆积: 如果发现 /var/lib/docker/overlay2 异常庞大,严禁手工去该目录删除层文件,这会破坏 Docker 容器镜像的元数据关联。应当使用 Docker 提供的生命周期命令:
    docker system df
    docker system prune -a --volumes

5. 存储深度概念:磁盘块分配与文件名义长度
#

运行 dust 时,可能会发现它的统计值与某些通过 ls -l 看到的值不一致。这是因为文件存在两种不同的大小口径:

Apparent Size (名义大小/文件长度):文件逻辑上包含的字节数
Disk Usage (物理磁盘占用):操作系统为该文件实际分配的存储块(Blocks)总和
  • 默认行为:dust 默认统计物理分配的磁盘块(类似于 du),这是判断磁盘空间满溢的真实指标;
  • 名义大小参数(-s, --apparent-size):使用逻辑长度进行统计。

为什么两者会有巨大差异?
#

  1. 小文件空间放大:Linux 文件系统(如 ext4)通常以 4096 字节(4 KiB)为一个 Block。一个只包含 10 个字节的文本文件,在磁盘上也必须分配一个完整的 4 KiB 块。如果目录内有 100 万个微小文件,名义大小可能只有 10 MB,但物理占用高达 4 GB。
  2. 稀疏文件(Sparse Files):某些数据库文件、虚拟机镜像或日志截断文件,名义长度可能有 100 GiB,但实际写入的非空块只有 2 GiB。如果不加说明地按 -s 扫描,会误以为该文件吞噬了整块磁盘。
  3. 压缩文件系统与去重:在支持透明压缩的 ZFS 或 Btrfs 上,物理占用可能远小于名义大小。

验证单个疑难文件时,可使用系统命令对照核查:

stat <file-name>
du -h <file-name>
du -h --apparent-size <file-name>

6. 排查隐蔽故障:Inode 耗尽与已删除未释放
#

在排障实践中,经常会遇到两次“诡异”的满盘现象:

现象 A:磁盘字节明明很空,却报错“No space left on device”
#

这是典型的 Inode(索引节点)耗尽。Linux 文件系统创建每个文件都需要消耗一个 Inode。当微小文件数量超出上限时,磁盘即使还有数百 GiB 空间也无法新建任何文件。

  1. 使用 df -i 检查各分区的 Inode 使用率;
  2. dust 提供了专门的 Inode / 文件计数模式:
    dust -f -d 2 /path
    使用 -f, --filecount 时,输出的不再是字节数,而是该目录下包含的子文件数量。你可以像排查体积一样,迅速找到哪个目录下堆积了数百万个无效 Session 文件或临时锁文件。

现象 B:df 显示 100% 满,但 dust 怎么扫都找不到大文件
#

如果 dust 统计出的所有文件体积加起来只有 20 GiB,但 df 显示 100 GiB 磁盘已满,常见原因包括:

  1. 进程持有已删除文件的句柄:当一个大日志文件被 rm 移除后,如果有运行中的守护进程(如 nginx 或 java)仍然打开着该文件的句柄,文件系统就不会释放其占用的磁盘块。使用以下命令找出被持有者:
    sudo lsof +L1
    # 或过滤 deleted
    sudo lsof | grep deleted
    释放方法是平滑重启(graceful reload)或重启对应的应用程序,让其关闭文件句柄,内核随后会自动回收磁盘空间。
  2. 挂载点覆盖(Mount Shadowing):如果在 /mnt/data 目录原本就有 50 GiB 文件的情况下,将另一块新磁盘挂载到了 /mnt/data 上,原有文件会被新挂载点“遮盖”。底层原文件依然占据根分区空间,但所有对该路径的扫描都只能看到新磁盘的内容。

7. WSL2 环境中的磁盘空间治理陷阱
#

在 WSL2(Windows Subsystem for Linux)下使用 dust 时,必须了解其背后的虚拟化存储机制:

  1. WSL2 原生虚拟磁盘(ext4.vhdx):在 WSL2 内部的 /home 或 /var 中删除数十 GiB 文件后,在 Windows 宿主机上会发现 ext4.vhdx 文件的大小完全没有减少。这是因为虚拟硬盘文件默认只会扩容、不会自动动态收缩。
    • 若要回收 Windows 宿主磁盘空间,需要在 Windows PowerShell 中执行 WSL 磁盘压缩或配置 sparse 属性:
    wsl --manage <Distro> --set-sparse true
  2. 跨系统扫描性能剧烈下降:如果在 WSL2 中执行 dust /mnt/c/Users,数据需要跨越 9P/virtio-fs 虚拟化总线,且受宿主 Windows Defender 实时文件监控影响,扫描速度会比在 Linux 原生文件系统上慢数倍至数十倍,并产生高 CPU 占用。排查 Windows 目录时,优先在 Windows 宿主使用原生工具。

8. 工具选型矩阵:dust、du、ncdu 与 df
#

在实际运维与开发工具链中,这四个工具应当各司其职:

工具优势与核心定位不适用场景
df毫秒级瞬时查看文件系统容量与 Inode 总览无法知道空间具体在哪个子目录
dust快速人工交互分析,比例直观,无需记忆复杂管道组合自动化 Shell 脚本解析、缺少交互式删除入口
ncdu基于 ncurses 的双向交互界面,支持在 TUI 内逐层穿透与确认删除快速打印一张输出直接离开终端的场景
duPOSIX 标准工具,全平台默认内置,适合脚本稳定输出与机器解析人工直观阅读体验差,排查深层目录需要拼装多段管道

脚本编程建议:严禁在自动化运维脚本中通过 awk 或正则去截取 dust 的彩色终端树。dust 的字符宽度、ANSI 颜色与条形图格式会随版本变化。在脚本中请始终使用标准的 du -sh 或 du -b。

9. 稳妥的磁盘空间排查实战路径
#

在处理磁盘空间报警时,建议遵循以下五步闭环:

# 步骤 1:确认告警挂载点与 Inode 状态
df -h
df -i

# 步骤 2:限定同一文件系统,用深度参数粗筛顶层大分支
dust -x -d 2 -n 15 /var

# 步骤 3:针对可疑大项进行聚焦展开
dust -x -d 3 -n 20 /var/log

# 步骤 4:若怀疑单个大文件,直接拉取文件列表
dust -x -F -n 10 /var/log

# 步骤 5:核实文件属性后再做决策
ls -lh /path/to/large_file
stat /path/to/large_file

在进入任何删除步骤之前,必须核实五个关键要素:该文件由哪个服务生成?是否有进程正在写入?该文件是否为业务关键日志?是否存在专用的清理命令?删除后能否自动恢复? 只有全部明确后,才能执行安全清理。

参考资料
#


本文采用 CC BY-NC-SA 4.0 许可。

modern-cli - 这篇文章属于一个选集。
§ 12: 本文

相关文章