運維高頻場景:rm 刪除超大日志文件,df -h 顯示磁盤佔用毫無變化。根因在於 文件被進程持有打開,目錄項 (dentry) 已刪除,但 inode 連接數 > 0,數據塊不回收。本文提供標準排查與零停機釋放方案。
rm 僅刪除目錄項,若進程持有文件描述符 (fd),inode 連接計數不歸零,數據塊標記為「使用中」df 統計數據塊使用量,du 遍歷目錄項統計,故 df > du# 1. 定位大文件 (示例:/tmp/access_log 66G)
du -s /tmp/* | sort -nr | head -3
# 2. 刪除文件
rm /tmp/access_log
# 3. 發現 df 未釋放,查找持有進程
lsof | grep deleted
# 輸出示例:
# httpd 1234 root 4u REG 253,0 70G 12 /tmp/access_log (deleted)
關鍵列:PID (進程 ID)、FD (文件描述符)、SIZE (當前大小)、(deleted) 標記。
| 方案 | 操作 | 優點 | 缺點/風險 |
|---|---|---|---|
| 殺掉進程 | kill -9 1234 | 徹底釋放 | 業務中斷、數據丟失風險 |
| 重啟服務/機器 | systemctl restart httpd | 安全釋放 | 停機時間長、影響面大 |
| 在線清空 (推薦) | > /tmp/access_log 或 echo "" > /tmp/access_log | 零停機、即時釋放、進程繼續寫入 | 需確保進程以追加模式寫入 |
# 方法 1:重定向清空 (最常用)
: > /tmp/access_log
# 或
echo "" > /tmp/access_log
# 方法 2:truncate 系統調用 (需 root)
truncate -s 0 /tmp/access_log
> 以 O_TRUNC 打開文件,內核將文件大小置 0,釋放數據塊,文件描述符保持有效write() 從偏移量 0 繼續寫入,邏輯無感logrotate 定期切割壓縮,copytruncate 模式無需重啟df -h 使用率 > 80% 觸發巡檢