LOADING

如果載入速度偏慢,請確認已啟用快取 (瀏覽器預設會開啟)

線上排障實戰:硬碟 100% 滿載且「禁止重啟」的日誌清空法與 rm 誤刪救援

在維護伺服器時,我們偶爾會遇到一個巨大的日誌檔案把硬碟空間佔到了 100%,然後一時手快直接用 rm 命令刪了,卻發現磁碟空間完全沒有被釋放

通常情況下,這時候只要把服務重啟下,空間就會被釋放出來。但如果今天遇到的是 不允許重啟服務 的情況,該如何在不停機的情況下把十 GB 的空間謄出來呢?


為什麼用 rm 刪除後空間沒釋放

在 Linux 的檔案系統中,當一個檔案仍然被某個運行中的行程 (Process) 開啟與引用時,即使你在硬碟目錄下用 rm 刪除了它,系統核心仍然會保留這個檔案的 Inode 與實體資料區塊,直到沒有任何行程佔用為止。這就是為什麼「檔案不見了,磁碟卻還是滿的」。(Windows 下是直接不讓你刪除檔案)

既然不能動業務進程,我們就換個思路:直接去記憶體裡找出它的檔案指標,然後清空它。


正確作法

如果你還沒按下 rm千萬不要刪除檔案。最安全且不需要重啟服務的做法,是直接把檔案的內容「抽乾」,保留空殼給進程繼續寫入。

你可以直接在終端機對著該日誌檔使用空重定向

> app.log

執行後,幾十 GB 的空間會瞬間釋放,且服務完全無感,依然能正常將新日誌寫入該檔案。


已經用 rm 刪除了怎麼辦?

如果你已經把檔案刪了,陷入了死局。既然不能動業務進程,我們就換個思路:直接去記憶體裡找出它的檔案指標,然後清空它。


第一步:順藤摸瓜,找出被隱藏的檔案指標

首先,我們需要找出系統裡「已經被刪除,但在記憶體裡依舊活躍」的檔案。使用 lsof 命令配合 grep 來過濾:

ubuntu@ubuntu-2204:~$ lsof | grep deleted
python3 21421 ubuntu    3w   REG    8,1 4295258893 290910 /home/ubuntu/app.log (deleted)

這個指令會列出系統裡所有已經被刪除,但在記憶體裡還活躍的檔案

從輸出結果找到對應的日誌檔案,並記下最前面的 PID(例如這裡的 21421)與 FD(3w 代表 3)
這個檔案在系統內核中會被標註為 (deleted)


第二步:深入 /proc 內核偽目錄

雖然檔案在硬碟目錄下已經消失,但在 Linux 核心的 /proc 目錄中,還記錄著該行程在記憶體中的運行狀態。我們進入該行程的 FD 目錄查看:

ubuntu@ubuntu-2204:~$ ls -l /proc/21421/fd
total 0
lrwx------ 1 ubuntu ubuntu 64 Jun 20 10:15 0 -> /dev/pts/0
lrwx------ 1 ubuntu ubuntu 64 Jun 20 10:15 1 -> /dev/pts/0
lrwx------ 1 ubuntu ubuntu 64 Jun 20 10:15 2 -> /dev/pts/0
l-wx------ 1 ubuntu ubuntu 64 Jun 20 10:15 3 -> '/home/ubuntu/app.log (deleted)'

在這裡,你會看到一個名為 3 的軟連結(Symlink),它指向的就是你剛剛刪掉的那個日誌檔案,後面通常還會標註著 (deleted)。這個 3 就是目前還在佔用實體磁碟空間的記憶體指標。


第三步:空重定向強行截斷數據

最關鍵的一步來了!既然指標還在,我們就可以順著這個指標,強行清空它所指向的數據。

直接在終端機中使用空重定向 (>),將大小為 0 的內容覆蓋進去:

> /proc/21421/fd/3

按下 Enter 的瞬間,被佔用的十幾 GB 空間就會立刻被核心清空回收,磁碟警報解除,而且業務進程完全不需要重啟!

前後變化

ubuntu@ubuntu-2204:~$ df -h
Filesystem      Size  Used Avail Use% Mounted on
tmpfs            94M  1.2M   93M   2% /run
- /dev/sda1       9.8G  6.5G  3.3G  67% /
+ /dev/sda1       9.8G  2.5G  7.3G  26% /
tmpfs           470M     0  470M   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
/dev/sda15      105M  6.1M   99M   6% /boot/efi
tmpfs            94M  4.0K   94M   1% /run/user/1000

避坑

經過上述的極端救援操作後,這個檔案現在已經變成一個「沒有名字的黑戶」,全靠著進程吊著一口氣。

如果你需要保留接下來新產生的日誌數據,請在未來重啟該服務之前,先把它備份出來。否則一旦進程終止,核心就會立刻將裡面的資料徹底銷毀:

cp /proc/21421/fd/3 /var/log/app.log

備份完成後,再找合適的時間重啟服務,讓系統恢復正常的日誌寫入機制即可。


附下圖片

Termius