題目與適用情境
凌晨 02:00,應用程式寫入 /var 時開始收到 ENOSPC。主機資料如下:
$ df -B1 /var
Filesystem 1B-blocks Used Available Use% Mounted on
/dev/nvme0n1p3 214748364800 210453397504 0 100% /var
$ sudo du -x -B1 -s /var
126701535232 /var
$ df -i /var
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/nvme0n1p3 20000000 4200000 15800000 21% /var換算後,檔案系統總量為 200 GiB,df 統計已用 196 GiB,du 只能走訪到 118 GiB,已用空間 相差 78 GiB。inode 使用率只有 21%,所以 inode 耗盡不是眼前原因。應用程式以一般使用者執行, 主機不能重新啟動,在確認檔案擁有者和用途之前也不能刪除任何資料。
這是一道 Linux 生產環境排障題。高品質回答不會從刪除最大的可見檔案開始,而會先證明兩個 工具觀察的是同一檔案系統、同一掛載命名空間、同一時間區間、同一單位和同一權限範圍,再 解釋哪些已配置空間可能不在可見目錄樹中,最後選擇影響範圍明確的復原動作。
面試官在評估什麼
第一項訊號是正確的統計模型。df 向已掛載檔案系統讀取整體區塊統計;du 走訪有名稱、 可存取的檔案和目錄,估算這些目錄項目對應的已配置區塊。兩者統計的是相關但不同的集合。 已取消連結卻仍被程序開啟的檔案,或被後續掛載遮住的底層目錄,仍占用檔案系統區塊,卻無法 從目前目錄樹按名稱走訪到。
第二項訊號是控制統計範圍。拿 df /var 與會跨檔案系統的 du /var 比較、其中一個命令在 容器內執行、忽略權限錯誤,或在日誌快速成長時先後取樣,都會人為製造差異。候選人應先統一 掛載目標、掛載命名空間、檔案系統邊界、位元組單位、權限和觀察區間,再判斷根因。
第三項訊號是安全處置。lsof +aL1 /var 能找出該檔案系統中連結數小於 1 的已開啟檔案, 但輸出只是證據,不代表可以直接終止程序或截斷描述元。強回答會確認服務負責人、檔案描述元、 裝置和成長狀態,優先使用應用程式支援的日誌重新開啟操作或正常重新啟動,同時驗證空間回收 和應用程式健康。
第四項訊號是拆開相似現象。ext4 保留區塊會減少一般程序可用的空間,使 Size - Used 大於 Avail;它不能解釋為什麼 df 統計的已用空間比同檔案系統的 du 多 78 GiB。inode 耗盡 同樣會回傳 ENOSPC,但題目給出的 21% 已排除這條路徑。寫入時複製快照、壓縮和配額需要 對應檔案系統的工具,不能照搬 ext4 命令。
最後一項訊號是收尾。回答需要保留處置前後證據,說明回收的位元組來自哪裡,確認寫入程序 已重新開啟正確路徑,檢查已刪除但仍開啟的檔案是否繼續成長,並改善日誌輪替或掛載變更監控。 只看到 df 百分比下降,不能證明應用程式復原或資料無損。
回答前要先確認的問題
- 兩個命令是否在同一掛載命名空間執行? 如果一個在主機、另一個在容器或服務命名空間,
/var 可能對應不同掛載。排查應進入受影響程序的命名空間,或明確只使用主機視角。
- 究竟哪個路徑寫入失敗,它屬於哪個檔案系統?
findmnt -T能把任意路徑對應到掛載點。
巢狀掛載或 bind mount 會改變應該拿哪組 df 和 du 資料比較。
- 取樣時間、單位和權限是否一致? 快速成長的日誌會在兩次命令之間變化;可讀格式會
四捨五入;無法存取的目錄會讓一般使用者執行的 du 少算。
- 涉及哪些檔案系統和儲存層? ext4、XFS、Btrfs、ZFS、overlay、LVM 快照和雲端磁碟
快照的統計與復原手段不同。
- 耗盡的是資料區塊、inode 還是配額?
df -i、配額工具和應用程式錯誤決定分支。刪除
一個大檔案不能解決 inode 耗盡,全域有空閒區塊也不能繞過使用者或專案配額。
- 哪些復原動作獲准執行? 重新開啟日誌、正常重載、正常重新啟動、容錯移轉和短暫維護
時段的可用性風險不同。緊急截斷描述元需要明確負責人和復原方案。
- 需要在多久內恢復多少餘裕? 目標決定先限制寫入、擴充容量、切換流量還是回收已確認
的空間,但不能成為刪除未知資料的理由。
30 秒回答架構
「我會先停止破壞性操作,用 findmnt、df -B1 和 sudo du -x -B1 確認相同路徑、檔案 系統、掛載命名空間、時間、權限和位元組單位。inode 只有 21%,所以我會量化 78 GiB 的區塊 差額,並用 lsof +aL1 /var 查找已取消連結但仍被程序開啟的檔案。如果它能解釋差額,我會 核對 PID、描述元、裝置和服務負責人,再走應用程式支援的日誌重新開啟或正常重新啟動,並 確認空間返回。如果不能解釋,我會檢查被掛載遮住的目錄、權限遺漏和檔案系統特有的中繼資料 或快照。ext4 保留區塊能解釋一般程序可用空間為零,解釋不了 78 GiB 的已用空間差額。最後 我會重測原命令、應用程式寫入、日誌和復發指標。」
分步深入解答
先讓比較可以重現。盡量在接近的時間收集失敗路徑、目前命名空間、掛載來源、檔案系統類型、 區塊統計、inode 統計和 du 總量:
readlink -f /var
findmnt -T /var -o SOURCE,FSTYPE,OPTIONS,TARGET
df -B1 /var
df -i /var
sudo du -x -B1 -s /var-x 限制 du 只統計 /var 所在檔案系統,不把巢狀檔案系統加進總數。-B1 消除區塊 單位歧義。應以足夠權限執行 du 並閱讀診斷資訊;把權限錯誤靜默丟棄,會把存取問題誤判成 儲存問題。命令還必須來自同一掛載命名空間。寫入方在容器內時,應有意識地比較主機視角和 nsenter 視角,不能因路徑字串相同就假設物件相同。
觀察到的差額是一項排障指標,不是等著被找到的單一檔案:
same_filesystem_gap = df_used_blocks - du_reachable_allocated_blocks
= 196 GiB - 118 GiB
= 78 GiB這個等式是近似分解:檔案系統中繼資料、配置粒度、並行寫入、寫入時複製共享、壓縮和工具 語意無法組成嚴格互斥的帳本。但穩定的 78 GiB 差額不可能只靠顯示四捨五入解釋。此時應先找 目錄樹之外仍占區塊的物件,而非繼續找另一個一般大路徑。
最有價值的檢查是最終目錄連結已刪除、程序卻仍保持開啟的檔案:
sudo lsof +aL1 /var
# After selecting a candidate from lsof, verify the live descriptor.
sudo readlink /proc/2481/fd/7
sudo stat -Lc 'device=%d inode=%i size=%s blocks=%b block_size=%B' /proc/2481/fd/7Linux 的 unlink 刪除的是名稱。如果它是檔案的最後一個連結,但程序仍保持檔案開啟,檔案 和資料區塊要等最後一個相關描述元關閉後才釋放。du 無法透過目錄樹找到該 inode,df 仍會 統計它的已配置區塊。常見事件路徑是日誌輪替錯誤:日誌檔案被刪除或改名,寫入程序卻繼續寫 舊描述元。
不能把 lsof 的 SIZE/OFF 對所有稀疏檔案或特殊檔案都當作精確可回收量。先確認描述元指向 目標裝置上的一般檔案、連結數為零、由哪個程序持有、是否仍在成長。一個檔案解釋不了大部分 78 GiB 時,要繼續比對多個大描述元。
建議的復原順序是:應用程式專用的重新開啟操作、正常重載、正常重新啟動或容錯移轉,最後才 是緊急介入。受支援的日誌重新開啟能讓程序關閉舊描述元並開啟目前路徑,不必終止整台主機。 受控服務重新啟動同樣能釋放描述元,但要考慮副本、就緒狀態和正在處理的工作。先發 SIGKILL 會繞過清理路徑。檔案已取消連結後,再執行 rm 也不會釋放活動描述元。
透過 /proc/PID/fd/FD 寫入可以在不停止程序時釋放空間,但只能作為最後手段。寫入方可能 保留舊偏移量,下一次寫入形成稀疏空洞、破壞應用程式格式或打破內部不變條件。只有在服務 負責人確認描述元和寫入語意、流量已受控、證據已保留且有復原方案後才能使用。通用操作手冊 不能把截斷描述元寫成預設修復。
如果 lsof 解釋不了差額,就檢查掛載拓撲。把另一個檔案系統掛載到非空目錄上,會遮住底層 目錄項目,但這些底層檔案仍占父檔案系統空間。findmnt 能顯示巢狀、bind 和重複覆蓋的掛載。 經核准的維護操作中,可以把 /var 非遞迴 bind 到 /var 之外的空目錄,在不中斷線上子掛載 的情況下觀察父檔案系統底層視圖:
sudo mkdir -p /mnt/var-underlay
sudo mount --bind /var /mnt/var-underlay
sudo du -x -B1 -s /mnt/var-underlay
sudo umount /mnt/var-underlay執行前必須依真實掛載樹驗證;命名空間傳播和平台政策可能改變結果。不能為了查看隱藏檔案 直接卸載繁忙的生產檔案系統。發現底層檔案後,仍要先確認擁有者和保留政策,再移動或刪除。
接著把「一般程序可用空間」與「已用空間差額」分開。ext4 的特權程序保留區塊可能讓應用 程式看不到原始空閒區塊。先檢查,不要修改:
source=$(findmnt -n -o SOURCE -T /var)
sudo tune2fs -l "$source" | grep -E 'Block count|Reserved block count|Block size'
sudo du --inodes -x -d1 /var | sort -n題目中總量減已用仍有 4 GiB,但 Avail 為零,符合部分空閒區塊不向一般服務開放的表現。 它能解釋眼前的寫入失敗,卻不能解釋 df 為什麼比 du 多統計 78 GiB 已用空間。事件中 降低保留比例會拿走特權守護程序的救命餘裕,也可能增加碎片風險;這應是容量決策,不能反射式 執行 tune2fs -m 0。
inode 耗盡是另一條獨立的 ENOSPC 路徑。本題 df -i 只有 21%,所以不是觸發因素。如果 達到 100%,應使用 du --inodes -x 定位小檔案密集目錄,只清理有保留政策涵蓋的資料。回收 資料區塊和回收 inode 是兩個目標。
最後才進入檔案系統特有的統計。GNU du 明確指出,寫入時複製共享、壓縮、備份區塊和網路 檔案系統都可能讓它的估算與裝置消耗不同。在 Btrfs 或 ZFS 上,應使用對應工具檢查子磁碟區 或資料集、快照、配額、獨占位元組和參考位元組;在 overlay 儲存上,要從擁有分層資料的 命名空間和執行環境排查。不能對 XFS 或 Btrfs 裝置執行 ext4 工具。
如果已開啟檔案、隱藏資料、存取錯誤、並行成長、保留可用量和檔案系統特性都解釋不了證據, 再檢查核心日誌和檔案系統健康。修復工具不是線上排障捷徑:先保留證據,遵循對應檔案系統的 官方流程,需要卸載的檢查應安排維護時段。
最後用同一組證據結束事件。重新執行 df -B1、df -i 和有權限的 du -x -B1;確認回收 位元組與已關閉或已清理的配置大致一致;驗證新的應用程式寫入;確認服務正在寫正確的命名 檔案;檢查延遲、錯誤、副本和資料完整性。後續監控應同時涵蓋區塊與 inode 餘裕、已刪除但 仍開啟的檔案成長、日誌輪替失敗、掛載拓撲變化和非預期快照成長。
高品質示範回答
「78 GiB 的差異是可能成立的,因為 df 和 du 的統計範圍不同。df 讀取檔案系統整體 區塊統計,du 走訪它能存取的命名目錄項目。我會先用 findmnt 對應 /var,在受影響服務 的掛載命名空間中執行兩個工具,統一位元組單位、root 權限、du -x 和取樣時間,先證明差額 真的存在。inode 只有 21%,這條分支可以暫時排除。
第一個假設是已刪除但仍開啟的檔案。我會執行 lsof +aL1 /var,再核對大型結果的 PID、檔案 描述元、裝置、inode、負責人和成長情況。如果日誌程序持有的空間接近差額,我會走它支援的 日誌重新開啟訊號或受控正常重新啟動。服務負責人確認影響之前,我不會終止程序或截斷 /proc。 描述元關閉後,我會確認 df 回收了預期範圍,應用程式也在寫新的命名日誌。
如果仍解釋不了,我會檢查 findmnt 是否存在遮住底層檔案的掛載,閱讀 du 權限錯誤,再用 檔案系統專用工具檢查快照、寫入時複製配置、配額和中繼資料。目前裝置是 ext4,所以還會 檢查保留區塊。保留區塊可以解釋為什麼總量減已用還有 4 GiB、應用程式可用量卻是零,但不能 解釋 78 GiB 的已用空間差額。
最後我會重跑原始測量,測試曾失敗的寫入路徑,檢查服務健康和資料完整性,並記錄究竟釋放了 哪部分配置。防止復發的工作是修正日誌輪替或掛載生命週期,同時監控區塊、inode 和已取消 連結卻仍開啟的檔案,避免檔案系統再次進入緊急保留區。」
常見錯誤
- 立即刪除最大的可見檔案 → 它可能是必要資料,也可能與不可見配置無關 → **先統一統計
範圍並確認擁有者,再修改資料。**
- 拿
df /var與du /比較 → 巢狀檔案系統和不同根目錄會讓減法失效 → **對應失敗
路徑,對同一檔案系統使用 du -x。**
- 忽略
du權限錯誤 → 有名稱但無法存取的檔案會被少算 → **用足夠權限執行並檢查每條
診斷。**
- 在不同掛載命名空間執行命令 → 同一路徑可能落到不同檔案系統 → **在受影響程序的
命名空間收集兩組資料。**
- 把 78 GiB 都稱為保留區塊 → ext4 保留影響一般使用者可用量,差額比較的是已用區塊和
可達配置 → 分別計算兩種差異。
- 對已刪除但仍開啟的檔案繼續執行
rm→ 檔名早已不存在,活動描述元仍持有 inode →
讓所屬程序關閉或安全重新開啟描述元。
- 把
kill -9當成第一個修復 → 突然終止可能遺失工作並繞過清理 → **優先使用受支援的
重新開啟、重載、正常重新啟動或容錯移轉。**
- 習慣性截斷
/proc/PID/fd/FD→ 保留的偏移和格式假設可能製造新損壞 → **只在語意已
驗證的核准緊急情況使用。**
- 為查看隱藏檔案直接卸載繁忙子掛載 → 相依服務可能立即故障 → **先檢查拓撲,使用核准
的替代視圖或維護時段。**
- 把 inode 用量併入位元組差額 → inode 耗盡是獨立的
ENOSPC原因 → **用df -i
單獨排查高檔案數目錄。**
- 對所有檔案系統套用 ext4 命令 → XFS、Btrfs、ZFS 和 overlay 的快照與配置語意不同 →
先確認 FSTYPE,再用對應工具。
- 看到
df降低就結束 → 寫入程序可能仍不健康或寫錯目標 → **驗證應用程式寫入、命名
檔案、資料完整性和復發指標。**
追問與回答
追問 1:如果沒有 lsof,或它看不到目標程序怎麼辦?
在與寫入方相同的 PID 和掛載命名空間檢查 /proc/PID/fd,查找連結目標以 (deleted) 結尾的 描述元,再核對裝置、inode、連結數和程序擁有者。權限、PID 命名空間或安全政策可能讓主機 lsof 漏掉容器程序。下一步仍不能自動變成截斷 /proc,復原決策必須按服務語意制定。
追問 2:如果 du 反而比 df 大呢?
先確認 du 是否走訪了巢狀檔案系統;du -x 可以排除這點。再檢查硬連結參數語意、 apparent-size 選項、並行刪除,以及寫入時複製或壓縮統計。du 估算指定目錄階層,df 統計 一個檔案系統,差異方向不同,優先懷疑的範圍錯誤也不同。
追問 3:換成 Btrfs 或 ZFS 後有什麼變化?
可見檔案大小不再足夠,因為快照和寫入時複製共享可能在路徑刪除後繼續保留區塊。要使用對應 檔案系統的空間、子磁碟區或資料集、快照和配額視圖,區分參考配置與獨占配置;只有在明確 保留政策下才能刪除快照。ext4 保留區塊和 tune2fs 結論不能移用。
追問 4:能否把 ext4 保留比例直接設為零救急?
只能在完成容量與可靠性審查後決定。保留空間讓特權程序繼續運作,也有助於控制碎片。降低 比例可能恢復一般使用者可用量,卻不會刪除已用區塊,也不能解釋未連結檔案的占用。應優先 回收或擴充已確認的容量,再依磁碟區用途和維運政策調整保留。
追問 5:怎樣安全重現已刪除但仍開啟的行為?
使用一次性檔案系統或測試主機:讓程序開啟一個大型測試檔案,在描述元仍開啟時取消路徑連結, 比較 df 與 du,透過 lsof +L1 觀察,再關閉描述元並確認資料區塊返回。不能在生產磁碟區 製造實驗,也不能借用真實服務的描述元。
追問 6:長期告警應該監控什麼?
依檔案系統和命名空間監控區塊與 inode 的耗盡時間和最小餘裕。增加已刪除但仍開啟的一般 檔案、日誌輪替失敗、快照成長和掛載拓撲變化的週期清單。告警應連到從統一統計範圍開始的 操作手冊,任何破壞性復原動作都需要資料或服務負責人核准。