CentOS 磁盘占用异常排查与处理手册(df 高、du/ncdu 低)
一、问题现象
典型表现:
df -h显示根分区使用率很高(如 90%)du/ncdu统计的文件总量明显偏小(如仅 15~18G)- 看起来"磁盘被占用",但找不到对应大文件
二、核心原因(本次实锤)
本次定位结果:大量 deleted-open 文件(已删除但仍被进程占用)导致。
- 文件已从目录中删除,
du/ncdu看不到 - 进程仍持有文件句柄,
df仍计算占用 - 最终发现
deleted-open total达到约 43GB
三、标准排查步骤
1) 看整体磁盘
bash
df -h
df -ih
2) 仅统计根分区真实目录占用(排除其他挂载干扰)
bash
sudo du -xhd1 / 2>/dev/null | sort -h
3) 检查 deleted-open 文件(关键)
bash
sudo lsof +L1 | head -n 50
sudo lsof +L1 | awk '{if($7 ~ /^[0-9]+$/) s+=$7} END {printf "deleted-open total: %.2f GB\n", s/1024/1024/1024}'
sudo lsof +L1 | sort -k7 -n | tail -n 30
4) 检查 Docker 占用(辅助)
bash
sudo du -xh /var/lib/docker 2>/dev/null | sort -h | tail -n 30
docker system df
四、处理策略(按优先级)
1) 第一优先:重启占用 deleted 文件的进程
关键点:不是继续删文件,而是让进程释放旧句柄。
- 若是 systemd 服务:
systemctl restart <service> - 若是宿主机手工启动 Java(本次就是):按服务逐个重启进程/应用
- 若是 Docker 容器:重启对应容器
docker restart <container>
2) 推荐重启顺序(低风险到核心)
- gateway
- oss
- auth
- api
- admin
每重启一个都复查:
bash
df -h /
sudo lsof +L1 | awk '{if($7 ~ /^[0-9]+$/) s+=$7} END {printf "deleted-open total: %.2f GB\n", s/1024/1024/1024}'
五、已验证结果(本次)
处理后根分区从高水位恢复到健康状态:
/dev/vda1:40G总量- 已用降至约
15G - 可用约
26G - 使用率约
36%
说明 deleted-open 空间已大幅释放,问题已解除。
六、残留项说明
执行 sudo lsof +L1 | head 可能仍看到少量 (deleted):
ctcm_agent的.log.old (deleted):通常体积小,可重启 agent 清理systemd/NetworkManager (deleted):常见于系统升级后旧进程未重启- 最干净做法:维护窗口
reboot - 不重启也可运行,只是句柄未完全清零
- 最干净做法:维护窗口
七、附加告警说明
lsof: no pwd entry for UID 27 含义:
- 有进程使用 UID 27,但
/etc/passwd无对应用户 - 一般不是本次磁盘异常主因
- 可作为后续系统账号治理项处理
八、预防建议(避免再次出现)
- 发布 Java 包时不要直接覆盖运行中的
.jar - 使用"新文件名发布 + 切换 + 重启旧进程退出"
- 日志轮转后确保应用重新打开日志文件(logback/log4j2 滚动策略)
- 定期巡检:
df -hlsof +L1/var/log、/var/cache/dnf、/var/lib/docker
九、常用清理命令(安全项)
bash
# 清理 dnf/yum 缓存
sudo dnf clean all
# 清理 btmp 历史并保留当前文件
sudo rm -f /var/log/btmp-*
sudo truncate -s 0 /var/log/btmp
注意:生产环境清理和重启建议在业务低峰进行。
十、值班速查版(10 条命令)
场景:
df很高,但du/ncdu看起来不高,怀疑幽灵占用。目标:5-10 分钟内定位并确认是否为 deleted-open 问题。
bash
# 1) 看根分区是否告警
df -h /
# 2) 看 inode 是否满
df -ih /
# 3) 看根分区目录占用(只看本分区)
sudo du -xhd1 / 2>/dev/null | sort -h
# 4) 看 deleted-open 明细(前50行)
sudo lsof +L1 | head -n 50
# 5) 统计 deleted-open 总量(GB)
sudo lsof +L1 | awk '{if($7 ~ /^[0-9]+$/) s+=$7} END {printf "deleted-open total: %.2f GB\n", s/1024/1024/1024}'
# 6) 看 deleted-open 最大的 30 条
sudo lsof +L1 | sort -k7 -n | tail -n 30
# 7) 看 Docker 总占用(辅助排查)
docker system df
# 8) 看 /var/lib/docker 末尾大项
sudo du -xh /var/lib/docker 2>/dev/null | sort -h | tail -n 30
# 9) 重启目标服务/进程后复核(将 <service> 替换为实际服务名)
sudo systemctl restart <service>
# 10) 再次确认空间是否回收
df -h /
sudo lsof +L1 | awk '{if($7 ~ /^[0-9]+$/) s+=$7} END {printf "deleted-open total: %.2f GB\n", s/1024/1024/1024}'
值班判断口诀
df高 +du低 +lsof +L1高 = deleted-open。- 继续删文件通常没用,关键是 重启占用句柄的进程。
- 先边缘服务后核心服务,逐个重启逐个复核。