萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 作業系統 >  >> Linux 教學

Linux 磁盤空間「失蹤」排查指南:隱藏文件、掛載遮蓋、稀疏文件三大真兇

df 顯示磁盤滿了,但 du -sh * 統計目錄大小總和卻遠小於已用空間——這是經典的「磁盤空間失蹤」現象。本文深度解析三大核心成因:隱藏文件統計遺漏、掛載點遮蓋原有數據、已刪除文件被進程持有(稀疏/洞文件),並提供一鍵排查腳本與預防措施。

現象複現與核心誤區


# df 顯示 /var 分區 95% 已用
df -h /var
# Filesystem      Size  Used Avail Use% Mounted on
# /dev/sda3       100G   95G  5.0G  95% /var

# du 統計卻只有 60G
du -sh /var/*
# 60G 總和
# 差額 35G 去哪了?
核心認知:df 統計**文件系統分配的塊**(含已刪除但未釋放的塊),du 統計**目錄樹下可見文件的塊**。兩者統計口徑不同,差異即為「幽靈佔用」。

真兇一:隱藏文件被 du 忽略

原理

du -sh * 的通配符 * **不匹配以點開頭的隱藏文件/目錄**(如 .git、.cache、.npm、.docker)。

排查命令


# 正確統計:包含隱藏項
du -sh /var/.[^.]* /var/* 2>/dev/null | sort -hr

# 或使用 --apparent-size 顯示表觀大小
du -sh --apparent-size /var

# 找出大隱藏目錄
find /var -maxdepth 2 -type d -name '.*' -exec du -sh {} \; 2>/dev/null | sort -hr | head

清理建議

  • /var/cache/、/var/tmp/:安全清理
  • /root/.cache/、/home/*/.cache/:用戶緩存,可清
  • /.snapshots/ (Snapper/Btrfs):快照佔用,按策略清理

真兇二:掛載點遮蓋原有數據

原理

將新分區掛載到**非空目錄**上,原目錄下的文件被「遮蓋」,du 見不到,但磁盤塊仍被佔用(因 inode 仍被引用)。

排查命令


# 1. 找出所有掛載點
findmnt -T /var
# 或
mount | grep /var

# 2. 檢查掛載點原目錄殘留數據
# 臨時掛載到別處查看
mkdir /tmp/var_orig
mount --bind / /tmp/var_orig
du -sh /tmp/var_orig/var   # 這裡能看到被遮蓋的數據
umount /tmp/var_orig

預防與修復

  • 規範:掛載點**必須為空目錄**
  • 修復:遷移數據 → 卸載 → 清理原目錄 → 重新掛載 → 遷回數據
  • 系統遷移場景:遷移 /var/lib/docker、/var/lib/mysql 時最易踩坑

真兇三:已刪除文件被進程持有(最隱蔽)

原理

進程打開文件寫入 → 文件被 rm 刪除(目錄項移除,inode 連接數歸零但>0) → 進程繼續寫入 → 數據寫入「無名」塊 → df 計入已用,du 遍歷不到 → 空間「失蹤」。

排查命令(核心技能)


# 1. lsof 找出已刪除但被持有的文件
lsof -nP | grep deleted
# 輸出示例:
# java      1234 user  100u   REG  253,0  10737418240  12 /var/log/app.log (deleted)

# 關鍵列:PID、FD、SIZE、PATH

# 2. 統計此類佔用總大小
lsof -nP | grep deleted | awk '{sum+=$7} END {print sum/1024/1024 " MB"}'

釋放空間(不重啟進程)


# 方法 1:通過 /proc 截斷文件(推薦,進程繼續運行)
# FD=100, PID=1234
: > /proc/1234/fd/100
# 文件大小歸零,空間即時釋放,進程可繼續寫入

# 方法 2:發送信號觸發日誌輪轉(如 logrotate 配置)
kill -USR1 1234  # 視應用支持而定

# 方法 3:重啟進程(終極方案)
systemctl restart app-service

一鍵全景排查腳本


#!/bin/bash
# /usr/local/bin/find_lost_space.sh
# 輸出:三大類失蹤空間的詳細清單

TARGET="${1:-/}"
echo "=== Lost Space Analysis for $TARGET ==="
echo "Timestamp: $(date)"
echo ""

echo "--- 1. Hidden files/dirs (du misses) ---"
du -sh ${TARGET}/.[^.]* ${TARGET}/* 2>/dev/null | sort -hr | head -20

echo -e "\n--- 2. Mount point masking ---"
findmnt -T "$TARGET" -o TARGET,SOURCE,FSTYPE,OPTIONS
echo "Checking underlying data..."
mkdir -p /tmp/root_bind
mount --bind / /tmp/root_bind
du -sh /tmp/root_bind${TARGET} 2>/dev/null
umount /tmp/root_bind

echo -e "\n--- 3. Deleted but held files (lsof) ---"
lsof -nP | grep deleted | awk '{printf "PID:%-8s FD:%-6s SIZE:%-12s CMD:%-15s FILE:%s\n", $2, $4, $7, $1, $9}'

echo -e "\n=== Summary ==="
df -h "$TARGET"
echo "Run with target path: $0 /var"

chmod +x /usr/local/bin/find_lost_space.sh
find_lost_space.sh /var

預防最佳實踐

  1. 日誌輪轉:配置 logrotate(copytruncate 或 sharedscripts + postrotate reload),避免手動 rm 導致持有
  2. 監控告警:監控 df vs du 差值,差值 > 10% 觸發告警
  3. 容器環境:Docker 容器內 df 看宿主機,du 看容器層,差異更大,需宿主機排查
  4. 定期巡檢:納入日常巡檢清單,lsof + grep deleted 必查項

磁盤空間「失蹤」不是鬼故事,而是 df/du 統計視角差異的必然結果。掌握 lsof + grep deleted、mount --bind 探底、隱藏文件統計三大核心技能,即可在 5 分鐘內定位 99% 的空間失蹤案件。

copyright © 萬盛學電腦網 all rights reserved