影评周公子 2026-04-01 21:05 采纳率: 98.9%
浏览 0
已采纳

`df -h` 和 `du -sh *` 结果差异大,如何准确判断磁盘空间真实占用?

**问题:** `df -h` 显示根分区使用率98%,但 `du -sh * | sort -hr | head -10` 总和仅占65%——空间“消失”了?这并非罕见故障,而是典型排查盲区。根本原因常为:① **已删除但进程仍占用的文件(lsof + /proc/*/fd 可查)**;② **隐藏的挂载点遮蔽(如 overlayfs、bind mount 导致 du 未遍历)**;③ **ext4/xfs 文件系统预留空间(默认5%,普通用户不可见)**;④ **快照或COW机制(LVM thin/LXC/ZFS)产生元数据开销**;⑤ **权限限制导致 du 跳过部分目录(如 /var/log/journal 权限受限时统计不全)**。单纯对比 df 与 du 结果易误判,需结合 `lsof +L1`、`find / -xdev -type f -size +100M -print0 | xargs -0 ls -lhS 2>/dev/null`、`debugfs -R "stats" /dev/sdX1` 等多维验证。真实占用 ≠ 可见文件总和,需穿透内核视图与用户视图的语义鸿沟。
  • 写回答

1条回答 默认 最新

  • 蔡恩泽 2026-04-01 21:05
    关注
    ```html

    一、现象层:理解 df 与 du 的语义鸿沟

    执行 df -h 显示根分区使用率 98%,而 du -sh * | sort -hr | head -10 仅统计出约 65% 的可见目录容量——这并非磁盘损坏,而是典型的“空间幻觉”。df 报告的是文件系统级(inode + data block)的已分配块总量,而 du 统计的是用户态可遍历路径下所有硬链接指向的文件数据块之和。二者视角根本不同:df 是内核眼中的“物理占用”,du 是 shell 用户眼中的“逻辑可见”。

    二、机制层:五大核心失配根源深度拆解

    序号原因类别技术本质典型场景验证命令示例
    已删除但被进程持有的文件(unlinked but open)文件 inode 未释放,dentry 已从目录树移除,但 fd 仍指向其 data blockslogrotate 后未重启 nginx;Java 应用持续写入被 rm 的日志
    lsof +L1find /proc/[0-9]*/fd -ls 2>/dev/null | grep deleted
    挂载点遮蔽(mount overlay / bind mount)du 默认递归遍历,遇子挂载点即停止(除非加 -x),导致底层被覆盖的目录未计入Docker 使用 overlay2;/var/lib/docker/overlay2 下存在巨量隐藏层;/tmp 绑定挂载自 tmpfs
    mount | grep -E "(overlay|bind|none)" + find / -xdev -type d -name "overlay2" 2>/dev/null
    文件系统预留空间(filesystem reserved blocks)ext4 默认保留 5% 块供 root 紧急使用(tune2fs -l /dev/sda1 | grep Reserved),df 计入但 du 不体现小容量根分区(如 20GB)上 5% = 1GB,对容量感知影响显著
    tune2fs -l /dev/sda1 | grep -i "reserved"xfs_info /(XFS 无此机制,但有 AG 预分配)

    三、诊断层:多维穿透式排查工作流

    graph TD A[启动排查] --> B{df -h / vs du -shx / 误差 >15%?} B -->|是| C[阶段1:检查 deleted-but-open 文件] C --> D[lsof +L1

    ls -l /proc/*/fd/ 2>/dev/null | grep deleted] D --> E{发现大量 deleted 文件?} E -->|是| F[定位 PID → lsof -p PID → kill/restart 进程] E -->|否| G[阶段2:检查挂载遮蔽与权限跳过] G --> H[mount -t overlay,bind,xfs,ext4 | grep ' / '] H --> I[find / -xdev -type f -size +100M -print0 2>/dev/null | xargs -0 ls -lhS] I --> J{/var/log/journal 权限是否为 0755?} J -->|否| K[chmod 0755 /var/log/journal && du -shx /var/log/journal]

    四、进阶层:快照与COW元数据开销不可忽视

    ZFS/LVM thin/LXC 容器快照虽不显式存于文件系统层级,但会占用同一 pool/vg 的物理块。例如:zfs list -t snapshot 可能揭示数百 GB 的 @autozsys_* 快照;lvs -o +seg_monitor,stripes,chunk_size 揭示 thin pool 元数据膨胀。XFS 的 reflink 和 ext4 的 project quota 也会引入间接引用开销。此时需运行:xfs_info / && xfs_db -r -c "freesp -s" /dev/sda1 对比空闲块一致性。

    五、工程实践:生产环境黄金排查清单

    1. ✅ 执行 sudo du -shx --max-depth=1 / 2>/dev/null | sort -hr | head -15-x 跨文件系统限制)
    2. ✅ 运行 sudo lsof +L1 | awk '{sum += $7} END {print "Total deleted-but-open size: " sum/1024/1024 " MB"}'
    3. ✅ 检查 journal 是否失控:journalctl --disk-usage;若超 2GB,执行 journalctl --vacuum-size=500M
    4. ✅ 验证 ext4 预留:sudo dumpe2fs -h /dev/sda1 | grep -i "block count\|reserved",计算预留块占比
    5. ✅ 排查 overlay2 层:sudo du -sh /var/lib/docker/overlay2/* 2>/dev/null | sort -hr | head -5
    6. ✅ 检查 LVM thin pool:sudo lvs -o+data_percent,metadata_percent,警惕 metadata 100% 导致写失败
    7. ✅ XFS 用户空间统计校验:sudo xfs_info / && sudo xfs_db -r -c "sb 0" -c "print" /dev/sda1
    8. ✅ 权限盲区扫描:sudo find / -xdev -type d ! -readable -o ! -executable 2>/dev/null | head -20
    9. ✅ 内核日志线索:dmesg -T | grep -i "disk full\|no space\|ENOSPC"
    10. ✅ 最终交叉验证:sudo debugfs -R "stats" /dev/sda1 2>/dev/null | grep -E "(Free blocks|Block size|Reserved block count)"

    六、认知升维:从“找大文件”到“建系统观”

    资深工程师不再满足于 du -sh /var/*,而是构建三层映射模型:① 用户视图(POSIX 路径 + 权限 + 硬链接);② 内核视图(VFS superblock + dentry cache + page cache + block device layer);③ 存储栈视图(LVM/ZFS pool → physical extent → SSD FTLC)。每一次 df-du 差异,都是这三层间语义转换失败的显影。真正的容量治理,始于理解 stat() 系统调用如何通过 generic_fillattr() 将磁盘块映射为 st_blocks,终于在 /proc/mounts/sys/fs/ 中完成全栈对齐。

    ```
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 已采纳回答 4月2日
  • 创建了问题 4月1日