du(磁盘使用量)和df(磁盘文件系统)显示不一致是常见问题,主要原因和处理方法如下:
一、常见原因
1. 已删除文件仍被进程占用
# 查看被删除但未释放的文件
lsof | grep deleted
# 或
lsof +L1
# 结果示例:
# process_name 1234 user 5r REG 253,0 100M 12345 /path/to/file (deleted)
处理:重启相关进程或发送信号释放文件句柄。
2. 文件系统预留空间
默认保留5%空间给root用户(ext3/4文件系统)。
# 查看预留比例
tune2fs -l /dev/sda1 | grep "Reserved block count"
# 调整预留比例(如改为1%)
tune2fs -m 1 /dev/sda1
3. 稀疏文件(Sparse Files)
# 创建稀疏文件示例
dd if=/dev/zero of=sparse_file bs=1M seek=1024 count=0
# du显示实际占用,df显示逻辑大小
du -sh sparse_file # 显示实际大小
ls -lh sparse_file # 显示逻辑大小
4. 日志文件系统待写入数据
# 强制同步文件系统
sync
5. 容器/虚拟化层占用
# 检查overlay2、docker、lvm等
df -hT
lsblk
docker system df # Docker专用
二、诊断步骤
1. 对比检查
# 1. 查看df结果
df -h
# 2. 查看根分区实际使用
du -shx /* 2>/dev/null | sort -hr
# 3. 计算差值
df_size=$(df / | awk 'NR==2 {print $3}')
du_size=$(du -sx / 2>/dev/null | cut -f1)
echo "差值: $(( (df_size - du_size) / 1024 )) MB"
2. 查找大文件
# 查找大于100M的文件
find / -type f -size +100M 2>/dev/null | xargs ls -lh
# 使用ncdu交互式查看
ncdu /
3. 检查特殊文件
# 检查隐藏文件(以.开头)
du -sh /.* 2>/dev/null | sort -hr
# 检查/tmp
ls -la /tmp | head -20
三、处理方案
方案1:释放被占用的已删除文件
# 方法A:重启相关进程
# 找到占用进程后
kill -9 PID
# 方法B:清空日志文件(不要直接删除)
truncate -s 0 /var/log/syslog
# 或
cat /dev/null > /var/log/syslog
方案2:清理缓存
# 清理页面缓存
echo 1 > /proc/sys/vm/drop_caches
# 清理目录项和inode缓存
echo 2 > /proc/sys/vm/drop_caches
# 清理页面缓存、目录项和inode缓存
echo 3 > /proc/sys/vm/drop_caches
方案3:检查文件系统错误
# 卸载后检查(谨慎操作)
umount /dev/sda1
fsck -y /dev/sda1
mount /dev/sda1
方案4:容器/Docker清理
# Docker清理
docker system prune -a
# 清理overlay2
systemctl stop docker
rm -rf /var/lib/docker/overlay2/*
systemctl start docker
四、预防措施
定期监控
# 添加到crontab
0 * * * * df -h >> /var/log/disk_usage.log
日志轮转配置
# 检查logrotate配置
cat /etc/logrotate.conf
使用lsof监控
# 监控已删除文件
watch -n 60 'lsof | grep deleted | wc -l'
设置磁盘配额
# 启用配额
quotacheck -cug /home
quotaon /home
五、注意事项
- 生产环境谨慎操作:清理前先备份重要数据
- 避免直接删除日志:使用truncate或logrotate
- 注意容器环境:Docker/容器可能隐藏真实使用量
- 考虑时间因素:du需要遍历文件,大目录可能需要时间
六、自动化检查脚本
#!/bin/bash
# check_disk_discrepancy.sh
partition="/"
df_used=$(df -k $partition | awk 'NR==2 {print $3}')
du_used=$(du -sxk $partition 2>/dev/null | cut -f1)
diff=$((df_used - du_used))
diff_mb=$((diff / 1024))
if [ $diff_mb -gt 100 ]; then
echo "警告:$partition 分区 du/df 差值超过100MB"
echo "df已用: ${df_used}KB"
echo "du统计: ${du_used}KB"
echo "差值: ${diff_mb}MB"
# 查找可能的原因
echo "检查已删除但未释放的文件:"
lsof | grep deleted | head -5
fi
通过以上方法,基本可以解决和预防du/df不一致问题。