1. 从一次磁盘告警说起:为什么du比df更值得信赖?
那天下午,监控系统突然弹出一条告警:“服务器/home分区磁盘使用率超过 90%”。我第一反应是执行df -h,结果确实显示使用率高达 95%。按照常规思路,我登录服务器,准备清理一些日志或临时文件。然而,当我用du -sh /home去统计/home目录的实际大小时,却发现结果和df显示的差了将近 30GB。这“消失”的 30GB 空间去哪了?是du算错了,还是df在骗我?这个看似简单的磁盘空间问题,背后其实牵扯到 Linux 文件系统一个非常核心但容易被忽略的机制:已删除但未释放的文件。
对于很多刚接触 Linux 系统管理的朋友,甚至一些有经验的开发者,du(disk usage)和df(disk free)这两个命令常常被混用,或者只知其然不知其所以然。df告诉你文件系统层面的空间使用情况,而du则从文件层级统计空间占用。当两者数据对不上时,往往就是问题所在。网络上热词“centos du df 磁盘空间差太多”就是这种困惑的集中体现。本文将深入du命令的骨髓,不仅告诉你每个参数怎么用,更会结合文件系统原理、常见生产环境问题,让你彻底搞懂磁盘空间那点事,成为一个能精准定位空间问题的“空间侦探”。
2.du命令的核心原理与df的本质区别
要玩转du,首先必须理解它和df的根本不同。这不仅仅是两个命令的差异,更是两种统计视角的碰撞。
2.1df:文件系统块级别的“上帝视角”
df命令查看的是**文件系统(如 ext4, xfs)**的磁盘空间信息。它的数据直接来源于文件系统的超级块(superblock)。你可以把文件系统想象成一个巨大的仓库,仓库被划分成许多固定大小的“块”(block,通常是 4KB)。df汇报的是:这个仓库总共有多少块,已经分配(使用)了多少块,还剩多少块空闲。
它的计算非常直接:已用空间 = (总块数 - 空闲块数) * 块大小。这里有个关键点:即使一个文件只写了 1 个字节,它也会独占至少一个完整的块。这就是“块大小”对空间使用的影响。
2.2du:文件层级遍历的“会计视角”
与df的宏观统计不同,du命令的工作方式是遍历指定目录下的所有文件和子目录,然后累加每个文件实际占用的磁盘空间。这个“实际占用”通常指的是文件使用的块数乘以块大小。
这里就引出了两个核心概念:
- 逻辑大小 vs 物理大小:一个文本文件内容只有 “hello”(5字节),这是它的逻辑大小。但在磁盘上,它可能占用了一个 4KB 的块,这就是它的物理大小。
du默认报告的是物理大小(--apparent-size参数可以看逻辑大小)。 - 硬链接(Hard Link)的统计:这是导致
du统计“偏大”的一个常见原因。硬链接是同一个文件数据(inode)的多个路径入口。du在遍历时,会为每一个硬链接都累加一次该文件的大小。如果同一个文件有 10 个硬链接,du就会把它算 10 次。而df从块分配角度看,只算一份。所以,在存在大量硬链接的目录(如/usr下的某些库文件),du总和可能远大于df显示的使用量。
2.3 经典矛盾:du与df结果不一致的三大元凶
回到开头的案例,为什么数据对不上?主要有以下三个原因:
- 已删除但未关闭的文件(Deleted but not released):这是生产环境最常见的“幽灵空间”杀手。当一个进程打开了一个文件(例如,一个正在写入的日志文件),此时即使你用
rm命令删除了这个文件,只要进程没有关闭该文件的句柄,该文件所占用的磁盘块就不会被释放。从df视角看,这些块依然被占用;但从du视角看,因为文件路径已经消失,遍历时找不到这个文件,所以不会统计它。这就会导致df显示的使用率很高,而du统计的目录大小却很小。可以使用lsof | grep deleted命令来查找这类“幽灵文件”。 - 文件系统预留空间(Reserved Blocks):默认情况下,ext3/ext4 文件系统会为 root 用户保留 5% 的磁盘空间(对于 xfs,也有类似机制)。这部分空间是为了防止普通用户写满磁盘导致系统关键服务(如 root 写日志)崩溃。
df命令会将这块预留空间计入“已用空间”,而du自然不会去统计这块不属于任何文件的空间。 - 容器与虚拟化的影响:在 Docker、LXC 等容器环境下,或者使用
mount --bind绑定了目录时,可能会产生更复杂的空间视图重叠,需要结合df -i(查看 inode 使用)和du进行综合判断。
提示:当发现
df和du差异巨大时,第一个排查动作应该是lsof -n | grep deleted,这能解决八成以上的“磁盘空间神秘消失”问题。
3.du命令的实战语法与关键参数精讲
掌握了原理,我们再来细致拆解du这个工具本身。它的基础语法是du [选项] [文件或目录]。下面我们针对高频和易错参数进行深度解析。
3.1 基础输出:理解默认行为
不带任何参数运行du [目录],它会递归列出该目录下每一个子目录的磁盘使用情况,单位是 KB。输出可能非常冗长。
du /var/log这个命令会从/var/log开始,列出其下所有目录的占用,最后一行是/var/log的总计。对于快速查看,这并不友好。
3.2 核心参数:让输出变得高效有用
-h(或--human-readable): 这是最常用的参数,没有之一。它会将大小转换为人类易读的单位(K, M, G, T)。du -h /home-s(或--summarize):另一个最常用参数。它只显示指定目录的总计大小,而不列出其内部细节。-s和-h几乎总是结伴出现。du -sh /home # 查看/home目录的总大小 du -sh * # 查看当前目录下所有文件和目录各自的大小-c(或--total): 在最后产生一个总计。当查看多个独立项目时特别有用。du -sch /var/log/* # 查看/var/log下每个子项的大小,并显示总和--max-depth=N:控制遍历深度的神器。网络热词中就有du max depth,可见其重要性。它指定du统计到第几级子目录。du -h --max-depth=1 /usr # 只显示/usr下一级子目录的大小--max-depth=0的效果等同于-s,只显示当前目录总计。这个参数能帮你快速定位大空间消耗发生在哪一层级,是进行磁盘空间分析的第一步。
3.3 进阶参数:应对特殊场景
-x(或--one-file-system): 这是一个极其重要但常被忽略的参数。它让du只统计当前文件系统上的文件,忽略挂载点(mount point)。例如,你想统计根目录/的大小,但/home是一个独立分区并挂载在/home下。如果不加-x,du -sh /会尝试去遍历统计/home这个挂载点下的所有文件,这可能是另一个巨大的磁盘,导致统计时间漫长、结果错误。加上-x后,遇到/home就会跳过。du -shx / # 正确统计根分区本身的大小--exclude=PATTERN: 排除匹配模式的文件或目录。支持通配符。在分析空间时,你可能想排除某些已知的缓存目录(如node_modules或.git)。du -sh --exclude=“*.iso” --exclude=“./.cache” /data-a(或--all): 默认du只输出目录的大小。加上-a会同时列出所有文件的大小。输出会变得非常详细,通常需要结合sort命令使用。--apparent-size: 显示文件的“逻辑大小”(即ls -l看到的大小),而非“物理大小”。这在评估网络传输数据量或文件内容大小时有用,但对磁盘空间管理参考价值不大。-B(或--block-size=SIZE): 强制使用指定的块大小单位,如-BM表示以 MB 为单位输出,-BG表示以 GB 为单位。比-h更统一,适合脚本处理。
3.4 参数组合与经典使用范例
快速定位当前目录下哪个子目录最大:
du -sh --max-depth=1 | sort -hr这里
sort -hr是逆序排序(-r)人类可读的数字(-h)。这是空间清理前的标准侦察动作。找出指定目录下最大的10个文件(结合
find):find /var/log -type f -exec du -h {} + | sort -rh | head -10这个命令组合威力强大:
find找出所有文件,-exec du -h对它们执行du,然后排序取前10。统计某类文件的总大小:
find . -name “*.log” -type f -exec du -ch {} + | tail -1这能统计当前目录下所有
.log文件的总大小。跨文件系统,精确统计家目录大小:
du -shx ~因为
/home通常是独立分区,使用-x可以确保只统计用户家目录本身的内容,不会误入其他挂载点。
4. 生产环境实战:du在磁盘空间排查中的高阶应用
命令行参数是武器,而排查思路是兵法。下面我们模拟几个真实的生产环境场景,看如何运用du及其组合拳来解决问题。
4.1 场景一:根分区/空间告急,快速定位罪魁祸首
现象:df -h显示/分区使用率超过 95%,系统告警。
排查步骤:
全局扫描,确定方向:
cd / sudo du -sh --max-depth=1 | sort -hr这条命令会列出根目录下所有一级子目录的大小排序。通常,
/var、/usr、/home是怀疑对象。假设发现/var异常巨大。逐层深入,缩小范围:
cd /var sudo du -sh --max-depth=1 | sort -hr继续在
/var下执行,可能发现/var/log或/var/lib很大。定位具体文件或日志:
# 如果是日志目录 cd /var/log sudo find . -type f -name “*.log” -exec du -h {} + | sort -rh | head -20 # 或者使用更简单的命令查看大文件 sudo ls -lhS /var/log | head -20此时,你很可能发现某个应用(如 Nginx, Docker)的日志文件(如
app.log)已经增长到几十 GB。处理与确认:
- 对于日志文件,可以使用
truncate或echo “” > file.log清空(确保相关服务支持),或者配置日志轮转(logrotate)。 - 清理后,再次运行
du -sh /var/log和df -h确认空间是否释放。 - 注意:直接
rm大日志文件后,如果服务进程未重启,空间可能不会立即释放(即前述的“已删除未关闭文件”问题)。此时需要重启相关服务或使用truncate命令。
- 对于日志文件,可以使用
4.2 场景二:du与df差异巨大,寻找“幽灵空间”
现象:df显示磁盘快满了,但用du逐级统计,所有目录加起来的大小远小于df显示的已用空间。
排查步骤:
检查已删除未关闭的文件:
sudo lsof +L1 | grep deleted # 或者更精确地 sudo lsof | grep deleted这个命令会列出所有被进程打开但已被删除的文件(状态为
deleted),并显示其大小和持有它的进程 PID。你会看到类似这样的输出:java 12345 user 1w REG 8,1 1024000000 1234567 /path/to/file.log (deleted)这表示 PID 为 12345 的 Java 进程持有一个已删除的日志文件,该文件仍占用约 1GB 空间。
处理方案:
- 方案A(推荐):重启持有该文件的进程。重启后,操作系统会回收该文件描述符,空间立即释放。
- 方案B:如果无法重启,可以找到该进程,然后清空对应的文件描述符。首先找到文件描述符编号(上面输出中的
1w,1就是 fd):# 假设进程PID是12345,文件描述符是1 ls -lh /proc/12345/fd/1 # 然后清空它(危险!确保你知道在做什么) : > /proc/12345/fd/1注意:方案B有风险,可能中断进程的正常日志记录,仅作为临时应急手段。
检查文件系统预留空间:
sudo tune2fs -l /dev/sda1 | grep -i “block count” # 或者查看预留空间百分比 sudo tune2fs -l /dev/sda1 | grep -i “reserved”对于 xfs 文件系统,使用
xfs_info命令。如果预留空间比例过高(比如根分区 5% 对于大硬盘来说可能很大),可以考虑在磁盘空闲时适当调低(tune2fs -m 1 /dev/sda1调整为 1%),但这需要谨慎评估。
4.3 场景三:高效分析特定用户或目录的历史增长
需求:监控/data/uploads目录过去一周的空间增长情况,找出增长最快的子目录。
思路:结合find按时间过滤和du统计。
编写分析脚本:
#!/bin/bash TARGET_DIR=“/data/uploads” # 找到7天前修改过的所有文件和目录,统计大小 find “$TARGET_DIR” -type f -mtime -7 -exec du -ch {} + | tail -1这个脚本能统计过去7天内被修改过的文件的总大小。要更精细,可以每天运行一次
du -sh $TARGET_DIR并将结果记录到日志中,通过对比日志来观察增长趋势。使用
ncdu工具进行交互式分析: 虽然本文主角是du,但必须提一下它的“增强版”——ncdu。它是一个基于 curses 库的交互式磁盘使用分析器,可以看作du的图形化终端版本。# 安装 sudo apt install ncdu # Debian/Ubuntu sudo yum install ncdu # CentOS/RHEL # 使用 ncdu /data/uploads进入后,可以用方向键浏览,按
d删除文件,界面直观,分析效率远超手动执行du命令组合。
5. 性能、陷阱与替代方案:关于du你必须知道的几件事
du很强大,但并非没有缺点。了解它的局限和替代方案,能让你在合适的场景选择最合适的工具。
5.1du的性能瓶颈与优化
du需要遍历目录树并统计每个文件的磁盘块,对于包含海量小文件(如node_modules、邮件存储)的目录,du可能会运行得非常慢,I/O 压力巨大。
- 使用
-x避免跨文件系统:如前所述,这能避免无意义的遍历。 - 使用
--max-depth限制深度:如果你只关心顶层目录的大小,就没必要遍历到底。 - 在非业务高峰时段执行:对于大型目录的分析,最好在系统负载低的时候进行。
- 考虑文件系统特性:在
ext4文件系统上,du的元数据操作相对较重。而像btrfs或zfs这类支持快照和写时复制的文件系统,du的行为会更复杂,可能需要使用其自带的子命令(如btrfs filesystem usage)来获得更准确的空间信息。
5.2 常见陷阱与误区
- 权限问题:普通用户运行
du时,对于没有读权限的目录或文件,du会报错Permission denied并且不会统计其大小。这会导致统计结果偏小。因此,统计系统目录时,务必使用sudo。 - 符号链接(Soft Link):默认情况下,
du会统计符号链接文件本身的大小(很小),而不会追踪到链接指向的目标。如果你希望du统计链接目标的大小,需要使用-L(或--dereference)参数。注意:这可能导致重复统计(如果链接指向的是已统计过的目录内部)或循环链接问题。 - 稀疏文件(Sparse File):像虚拟机磁盘文件(
.qcow2,.vdi)或数据库文件,可能是稀疏文件。它们逻辑上很大,但物理占用可能很小。du默认报告物理占用,但du --apparent-size会报告逻辑大小,两者差异可能极大。 du统计的是磁盘占用,不是文件内容总和:这一点再怎么强调都不为过。一个 1KB 的文件占用 4KB 磁盘空间;一个 1000 个硬链接的文件,du会算 1000 次。这是理解du输出的一切基础。
5.3 替代与互补工具
df:永远的搭档,用于宏观把控文件系统容量和 inode 使用率(df -i)。ls:对于快速查看单个文件或少量文件的逻辑大小,ls -lh更直观。ncdu:如前所述,交互式分析的绝佳选择,尤其适合探索性排查。btrfs/zfs专用命令:如果你使用这些高级文件系统,请忘记du和df的常规输出,它们无法正确反映快照、克隆等特性下的空间使用。务必使用btrfs filesystem du、zfs list等原生命令。- 图形化工具:如
Baobab(GNOME 的磁盘使用分析器)、Filelight(KDE)等,在桌面环境下可以提供更直观的可视化分析。
du命令是 Linux 系统管理员的瑞士军刀之一,其价值远不止于一个简单的“查看文件夹大小”的工具。从理解其与df的本质区别开始,到熟练运用参数组合进行高效排查,再到洞察其背后的文件系统原理和性能陷阱,这是一个系统工程师成长的必经之路。下次再遇到磁盘空间告警时,希望你能像一位经验丰富的侦探,从容地拿起du这把放大镜,结合lsof、find等工具,迅速定位问题根源,而不是盲目地删除文件。记住,精准的洞察源于对基础工具的深刻理解。