一、現象描述
操作系統:CentOS 6.8 x64
使用 df -h 命令,看見 / 根目錄下磁盤空間已滿(100%),於是手動清理大日志文件。
[root@local ~]# df -h Filesystem Size Used Avail Use% Mounted on /dev/mapper/rootvg-LogVol00 59G 59G 0 100% / /dev/sda1 190M 13M 168M 8% /boot tmpfs 2.0G 0 2.0G 0% /dev/shm
通過 du -sh 命令,找到占用大量空間的日志文件,於是使用 rm -rf 刪除了它。
[root@local ~]# cd /var/nginx/logs/ [root@local ~]# rm -rf t-access.log t-error.log
然后 查看磁盤空間的使用情況,發現 / (根目錄)的空間並沒有發生變化。但是可以看到 Used 發生了變化。
[root@local ~]# df -h Filesystem Size Used Avail Use% Mounted on /dev/mapper/rootvg-LogVol00 59G 56G 0 100% / /dev/sda1 190M 13M 168M 8% /boot tmpfs 2.0G 0 2.0G 0% /dev/shm
這是怎么回事呢?
二、原因
未釋放磁盤空間的原因:
在Linux或者Unix系統中,通過rm或者文件管理器刪除文件將會從文件系統的文件夾結構上解除鏈接(unlink),然而假設文件是被打開的(有一個進程正在使用),那么進程將仍然能夠讀取該文件,磁盤空間也一直被占用。而我刪除的是nginx的訪問日志文件,在刪除的時候該文件正在被使用。
三、解決辦法
首先獲得一個已經被刪除的可是仍然被應用程序占用的文件列表。操作如下:
[root@local ~]# lsof |grep deleted nginx 4399 root 38w REG 253,0 19304448 10835682 /var/nginx/logs/t-access.log (deleted) nginx 4399 root 39w REG 253,0 3502080 10835684 /var/nginx/logs/t-error.log (deleted) nginx 4401 nobody 38w REG 253,0 19304448 10835682 /var/nginx/logs/t-access.log (deleted) nginx 4401 nobody 39w REG 253,0 3502080 10835684 /var/nginx/logs/t-error.log (deleted) nginx 4402 nobody 38w REG 253,0 19304448 10835682 /var/nginx/logs/t-access.log (deleted) nginx 4402 nobody 39w REG 253,0 3502080 10835684 /var/nginx/logs/t-error.log (deleted) nginx 4403 nobody 38w REG 253,0 19304448 10835682 /var/nginx/logs/t-access.log (deleted) nginx 4403 nobody 39w REG 253,0 3502080 10835684 /var/nginx/logs/t-error.log (deleted) nginx 4404 nobody 38w REG 253,0 19304448 10835682 /var/nginx/logs/t-access.log (deleted) nginx 4404 nobody 39w REG 253,0 3502080 10835684 /var/nginx/logs/t-error.log (deleted)
從輸出的結果可以看到 /var/nginx/logs/t-access.log 和 t-error.log 還在被使用中,所以導致未釋放空間。
那么如何讓進程釋放呢?
方法1:直接 kill 掉相應的進程,或者停掉使用這個文件的應用,讓操作系統自己主動回收磁盤空間。
由於還有其他項目正在使用該應用(nginx服務),所以不能停掉nginx服務,於是使用 kill 命令刪除相應的進程。
[root@local ~]# kill -9 4399 [root@local ~]# kill -9 4401 [root@local ~]# kill -9 4402 [root@local ~]# kill -9 4403 [root@local ~]# kill -9 4404
再次,查看磁盤空間的使用情況,發現空間已經被回收了。
[root@local ~]# df -h Filesystem Size Used Avail Use% Mounted on /dev/mapper/rootvg-LogVol00 59G 56G 0 95% / /dev/sda1 190M 13M 168M 8% /boot tmpfs 2.0G 0 2.0G 0% /dev/shm
方法2:以后清理正在被讀寫的大日志文件時,直接使用 echo "" > xxx.log 命令,即直接將文件置空,並不影響服務的使用,文件大小也被控制下來,磁盤空間也釋放了。
說明:
當Linux打開一個文件的時候,Linux內核會為每個進程在/proc/ 『/proc/nnnn/fd/文件夾(nnnn為pid)』建立一個以其pid為名的文件夾用來保存進程的相關信息,而其子文件夾fd保存的是該進程打開的全部文件的fd(fd:file descriptor)。
kill進程是通過截斷proc文件系統中的文件能夠強制要求系統回收分配給正在使用的的文件。這是一項高級技術,僅到管理員確定不會對執行中的進程造成影響時使用。應用程序對這樣的方式支持的並不好,當一個正在使用的文件被截斷可能會引發不可預知的問題。
四、刪除原理
一般來說,不會出現刪除文件后空間不釋放的情況,但是也存在例外,比如文件被進程鎖定,或者有進程在使用這個文件,例如輸出日志文件,要了解這個問題,就需要知道Linux下文件的存儲機制和存儲結構。
一個文件在文件系統中由兩個部分構成:數據和指針。指針位於文件系統的meta-data中,數據被刪除后,指針被清除,而數部分還是存儲在磁盤中,只不過數據對應的指針被清除后,文件數據部分占用的空間就可以被覆蓋了。之所以出現刪除大文件后,空間還沒有釋放,就是因為有進程一直在使用這個文件的指針,日志文件的服務還在運行,導致雖然刪除了日志大文件,但文件對應的指針部分由於被進程鎖定,並未從meta-data中清除,而由於指針並未被刪除,那么系統就認為文件並未被刪除,所以使用 df 命令查看還是 100%。