在Linux系统运维中,有时会遇到磁盘空间显示异常过大的情况:执行df命令发现某个分区已用空间接近占满,但通过du统计各目录实际文件大小却远小于此数值,或者磁盘明明还有容量却无法写入数据。这类问题通常不是真实数据暴涨,而是系统层面的空间统计出现了偏差。

一、常见原因分类
磁盘空间显示异常过大或不可用,主要由三类原因导致。其一是已删除文件仍被进程占用,文件在文件系统层面已被删掉,但打开该文件的进程没有关闭句柄,内核不会真正释放磁盘块,df统计的已用空间就包含这些“幽灵”空间。其二是inode耗尽,当分区中大量小文件占满了inode表,即便数据块还剩很多,新建文件也会报空间不足。其三是挂载点异常或循环挂载,导致du统计错位而df看到的是底层设备。
理解这些原因后,排查就有了方向。df读取的是文件系统超级块中的块分配计数,它反映的是内核视角的真实占用;du则是遍历目录树累加文件大小,两者口径不同,差异处往往就是问题所在。因此对比df与du的结果,是定位问题的第一步。
1.1 已删除文件被占用
这类情况在多进程服务(如Nginx、Java应用)长期运行且日志被rm删除但未重载时极为常见。进程持续往已删除的文件描述符写日志,空间只增不减。用如下命令可找出此类文件:
# 查找已被删除但仍被进程占用的文件 lsof +L1 | grep deleted # 查看具体某个分区的占用差异 df -h / du -sh /* 2>/dev/null
输出中SIZE栏显示文件大小,PID为持有进程。向该进程发送SIGTERM或重载配置通常能释放空间;若不能重启,可通过清空文件内容而非删除来过渡:
# 通过进程文件描述符清空已删除文件内容 pid=1234 fd=5 echo > /proc/$pid/fd/$fd
1.2 inode耗尽问题
inode是记录文件元信息的索引节点,每个文件或目录消耗一个。若分区充满几百万个空文件,inode用尽后df -i会显示使用率100%,但df -h可能还剩空间。此时需要用find统计各目录文件数:
# 查看inode使用情况 df -i / # 找出文件数量最多的目录 find /var -xdev -type f | cut -d/ -f2-3 | sort | uniq -c | sort -rn | head
清理时应批量删除无用碎文件,例如清理某缓存目录:
# 删除30天前的小文件 find /var/cache/app -type f -mtime +30 -delete
二、处理流程与工具
系统化的处理流程应先确认现象,再分层排查。先运行df -h与df -i确认是块空间还是inode异常;再用du -x按挂载点独立统计,排除其他分区干扰;最后用lsof查删除占用。整个过程无需重启系统,业务影响可控。
除了上述原生命令,也可用ncdu这类交互式工具快速可视化目录占用,避免手动比对。但在生产环境无外网时,原生命令更可靠。以下脚本可一键输出差异报告:
#!/bin/bash # 简单磁盘异常排查脚本 part=/ echo "df块使用:" df -h $part echo "df inode使用:" df -i $part echo "top目录占用:" du -x $part 2>/dev/null | sort -rn | head -10 echo "删除未释放:" lsof +L1 $part 2>/dev/null | grep deleted
该脚本将关键指标打印出来,方便比对。若du总和远小于df已用,且lsof发现大尺寸deleted文件,即可定位为首类原因。处理时优先重载服务而非kill,保障连接不中断。
三、预防与总结
建立日志轮转机制能从源头减少已删除占用问题。使用logrotate配置size与copytruncate,避免进程持旧文件。对于易产生碎文件的业务,单独划分区并监控inode。日常监控应同时采集df -h与df -i指标,设定阈值告警。
综上,Linux磁盘空间显示异常过大并非不可逆故障。掌握df与du口径差异、熟练用lsof查句柄、理解inode机制,就能在不停服情况下恢复真实空间状态。遇到此类告警,冷静分层排查往往比直接扩容更有效。