磁碟空間滿
由於Linux沒有回收站功能,所以線上伺服器上所有要刪除的檔案都會先移到系統/tmp目錄下,然後定期清除/tmp目錄下的資料。這個策略本身沒有問題,但是透過檢查發現這台伺服器的系統分區中並沒有單獨劃分/tmp分區,這樣/tmp下的資料其實佔用了根分區的空間。既然找到了問題,那麼刪除/tmp目錄下一些佔空間較大的資料檔案即可,檢查/tmp下最大的三個資料文。
du -sh /tmp/* | sort -nr | head -3
查看/tmp下最大的前三個資料檔案透過命令輸出發現在/tmp目錄下有個66GB大小的文件access_log,這個文件應該是Apache產生的存取日誌文件,從日誌大小來看,應該是很久沒有清理Apache日誌檔案了,基本判定是這個檔案導致的根空間爆滿,在確認此檔案可以刪除後,執行如下刪除操作:
rm /tmp/access_log
接著查看系統根分割區空間是否釋放,從輸出可以看到,根分割區空間仍然沒有釋放,這是怎麼回事?
刪除檔案空間不釋放
一般來說不會出現刪除檔案後空間不釋放的情況,但是也存在例外,例如檔案被進程鎖定,或者有進程一直在寫資料給這個檔案等,要理解這個問題,就需要知道Linux下檔案的儲存機制和儲存結構。
檔案的資料與指標部分
一個檔案在檔案系統中的存放分為兩個部分:資料部分和指標部分,指標位於檔案系統的meta-data中,將資料刪除後,這個指標就從meta-data中清除了,而資料部分儲存在磁碟中。在將資料對應的指標從meta-data中清除後,檔案資料部分所佔用的空間就可以被覆寫並寫入新的內容,之所以在出現刪除access_log檔案後,空間還沒釋放,就是因為httpd進程還在一直向這個文件寫入內容,導致雖然刪除了access_log文件,但是由於進程鎖定,文件對應的指針部分並未從meta-data中清除,而由於指針並未刪除,系統內核就認為文件並未刪除。
查找被應用程式佔用的已刪除檔案清單
因此透過df指令查詢空間並未釋放也就既然有了解決問題的思路,那麼接下來看看是否有進程一直在向access_log檔案中寫數據,這裡需要用到Linux下的lsof指令,透過這個指令可以取得一個仍然被應用程式佔用的已刪除檔案清單:
lsof | grep delete
從輸出結果可以看到,/tmp/access_log檔案被進程httpd鎖定,而httpd進程也一直向這個檔案寫入日誌資料。從第7列可知,這個日誌檔案大小約70GB,而係統根分割區總大小才100GB,由此可知,這個檔案就是導致系統根分割區空間耗盡的罪魁禍首。最後一列的「deleted」狀態說明這個日誌檔案已經被刪除,但由於進程還在一直向此檔案寫入數據,因此空間並未釋放。
正確地清空檔案
解決這一類問題的方法有很多種,最簡單的方法是關閉或重啟httpd進程,當然也可以重啟作業系統,不過這些並不是最好的方法。對待這種進程不停對文件寫日誌的操作,要釋放文件佔用的磁碟空間,最好的方法是在線清空這個文件,具體可以通過以下命令完成:
[root@localhost ~]# echo " " >/tmp/access_log
通過這種方法,磁碟空間不僅可以馬上釋放,也可保障進程繼續寫入日誌到檔案的日誌,此方法常用於線上清理Apache、Tomcat、Nginx等Web服務所產生的日誌檔案。