【摘要】
“磁盘空间不足”是Linux系统管理中最常见的警报之一,但使用df命令查看时,经常发现已用空间与文件大小总和严重不符。本文通过真实的故障排查案例,揭示被遗忘的日志文件、僵尸进程锁定文件、Docker容器碎片等”磁盘黑洞”的定位方法,提供一套即学即用的磁盘空间回收方案。
![图片[1]-Linux磁盘空间莫名消失?快速定位并清理隐藏的磁盘黑洞-Vc博客](https://blogimg.vcvcc.cc/2025/10/20251031141535504.jpg?imageView2/0/format/webp/q/75)
一、问题现场:磁盘告急,但找不到”元凶”
凌晨3点,监控系统发出磁盘空间告警:服务器根分区使用率超过95%。登录系统后执行常规检查:
# 查看磁盘使用情况
df -h
# 输出:/dev/sda1 使用率96%,只剩2.1G空间
# 查看各目录大小
du -sh /* | sort -hr
# 输出:/var 15G, /home 8G, /usr 6G... 但总和远小于磁盘使用量
这就是典型的”磁盘黑洞”现象:已用空间远大于可见文件总和。问题可能隐藏在以下几个地方。
二、罪魁祸首一:被进程锁定的已删除文件
1. 问题诊断与定位
# 查找被删除但仍被进程占用的文件
lsof +L1
# 或者更详细的查询
lsof | grep -i deleted
# 输出示例:
# java 1234 user 44u REG 8,1 1048576000 123456 /var/log/app.log (deleted)
# nginx 5678 root 17u REG 8,1 524288000 789012 /var/nginx/cache.tmp (deleted)
2. 问题解析与解决
当进程打开一个文件后,即使这个文件被删除,只要进程不退出,该文件占用的磁盘空间就不会释放。解决方案:
# 方法1:重启持有文件的进程(生产环境谨慎)
sudo systemctl restart application-service
# 方法2:清空文件内容(不中断服务)
# 找到持有文件的进程ID
pid=$(lsof | grep -i deleted | grep app.log | awk '{print $2}' | head -1)
# 清空文件内容
sudo truncate -s 0 /proc/$pid/fd/44
# 方法3:使用脚本批量清理
#!/bin/bash
echo "正在清理被锁定的已删除文件..."
lsof | grep -i deleted | while read line; do
pid=$(echo $line | awk '{print $2}')
fd=$(echo $line | awk '{print $4}' | tr -d 'u')
file_size=$(ls -l /proc/$pid/fd/$fd <strong>2</strong>>/dev/null | awk '{print $5}')
if [ "$file_size" -gt 104857600 ]; then # 大于100MB
echo "清理PID $pid 的FD $fd,释放 $((file_size/1024/1024))MB"
sudo truncate -s 0 /proc/$pid/fd/$fd
fi
done
三、罪魁祸首二:Docker容器产生的磁盘碎片
1. 诊断Docker磁盘使用
# 查看Docker总体磁盘使用
docker system df
# 详细查看各组件占用
docker system df -v
# 输出示例:
# Images 5.2GB
# Containers 3.1GB
# Local Volumes 12.4GB # 这是重点排查对象
# Build Cache 1.8GB
2. 清理方案与预防
# 一键清理无用资源
docker system prune -f
# 深度清理(包括未使用的镜像和构建缓存)
docker system prune -a -f --volumes
# 针对性的日志清理
# 查找Docker容器日志大文件
find /var/lib/docker/containers -name "*.log" -type f -size +100M
# 配置日志轮转(预防措施)
# 在/etc/docker/daemon.json中添加:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
四、罪魁祸首三:日志系统的”沉默吞噬者”
1. 定位日志文件黑洞
# 检查系统日志目录
du -sh /var/log/*
# 注意检查这些常被忽略的目录:
# /var/log/journal/ - systemd日志
# /var/cache/ - 应用缓存
# /var/tmp/ - 临时文件
# 检查journal日志大小
journalctl --disk-usage
# 输出:Archived and active journals take up 3.8G on disk.
2. 日志清理实战
# 清理systemd日志
sudo journalctl --vacuum-time=7d # 保留7天
sudo journalctl --vacuum-size=1G # 保留1GB
# 清理应用日志
sudo truncate -s 0 /var/log/mysql/slow.log
sudo truncate -s 0 /var/log/nginx/access.log
# 配置日志轮转(编辑/etc/logrotate.d/)
# 示例:nginx日志轮转配置
cat > /etc/logrotate.d/nginx << EOF
/var/log/nginx/*.log {
daily
missingok
rotate 7
compress
delaycompress
notifempty
create 644 nginx nginx
postrotate
/bin/kill -USR1 $(cat /var/run/nginx.pid <strong>2</strong>>/dev/null) 2>/dev/null || true
endscript
}
EOF
五、终极排查武器:磁盘空间分析脚本
1. 一键诊断脚本
<strong>#!/bin/bash</strong>
# disk_black_hole_detector.sh
echo "====== 磁盘空间黑洞检测报告 ======"
echo "生成时间: $(date)"
echo
# 1. 基础磁盘信息
echo "1. 磁盘使用情况:"
df -h | grep -v tmpfs
echo
# 2. 查找大文件
echo "2. 前10大文件:"
find / -type f -size +100M <strong>2</strong>>/dev/null | xargs -I {} du -h {} | sort -hr | head -10
echo
# 3. 检查被删除的锁定文件
echo "3. 被进程锁定的已删除文件:"
lsof +L1 <strong>2</strong>>/dev/null | awk '$5 ~ /REG.*deleted/ {print $2, $9, $5}' | head -10
echo
# 4. Docker磁盘使用
if command -v docker &> /dev/null; then
echo "4. Docker磁盘使用:"
docker system df <strong>2</strong>>/dev/null || echo "Docker未运行"
else
echo "4. Docker: 未安装"
fi
echo
# 5. 日志文件统计
echo "5. 日志文件大小:"
du -sh /var/log/* /var/log/journal/* <strong>2</strong>>/dev/null | sort -hr
echo
# 6. 特殊目录检查
echo "6. 缓存和临时文件:"
du -sh /tmp /var/tmp /var/cache <strong>2</strong>>/dev/null
2. 自动化清理脚本
<strong>#!/bin/bash</strong>
# safe_disk_cleaner.sh
echo "开始安全磁盘清理..."
# 1. 清理临时文件
echo "清理临时文件..."
sudo find /tmp -type f -atime +7 -delete
sudo find /var/tmp -type f -atime +30 -delete
# 2. 清理包管理器缓存
echo "清理包管理器缓存..."
if command -v apt-get &> /dev/null; then
sudo apt-get autoremove -y
sudo apt-get autoclean
elif command -v yum &> /dev/null; then
sudo yum autoremove -y
sudo yum clean all
fi
# 3. 清理日志(保留最近7天)
echo "清理旧日志..."
find /var/log -name "*.log" -type f -mtime +7 -exec truncate -s 0 {} \;
# 4. 清理用户缓存
echo "清理用户缓存..."
find /home -type f -name "*.cache" -size +10M -delete <strong>2</strong>>/dev/null
echo "清理完成!当前磁盘使用:"
df -h /
六、预防措施:建立磁盘空间监控体系
1. 定期检查任务
# 添加到crontab,每天检查一次
# 每天凌晨2点执行磁盘检查
0 2 * * * /opt/scripts/disk_black_hole_detector.sh >> /var/log/disk_check.log
# 每周日凌晨3点执行安全清理
0 3 * * 0 /opt/scripts/safe_disk_cleaner.sh
2. 实时监控告警
# 简单的磁盘监控脚本
#!/bin/bash
THRESHOLD=90
CURRENT_USAGE=$(df / | awk 'NR==2 {print $5}' | sed 's/%//')
if [ "$CURRENT_USAGE" -gt "$THRESHOLD" ]; then
echo "警告:根分区使用率 ${CURRENT_USAGE}% 超过阈值 ${THRESHOLD}%" | \
mail -s "磁盘空间告警 $(hostname)" admin@company.com
fi
【总结】
Linux磁盘空间”黑洞”问题通常源于被进程锁定的已删除文件、容器运行时碎片、无限制增长的日志文件等隐蔽因素。通过lsof排查锁定文件、docker system df分析容器占用、journalctl管理日志,结合自动化监控脚本,可以快速定位并回收丢失的磁盘空间。建立定期的磁盘健康检查机制,是避免类似问题再次发生的关键。
© 版权声明
THE END












暂无评论内容