案例現象 這天,監控系統發來一條告警消息,內容說某台伺服器根目錄磁碟占用空間達到閾值,超過百分之八十了 登上伺服器,df -Th 看一下,發現磁碟空間確實不夠用了 進入到根目錄,然後 du -sh * 可以看到,var 目錄下的磁碟空間已經占用了 75G 既然如此,刪除 var 目錄下一些占空間較大 ...
案例現象
這天,監控系統發來一條告警消息,內容說某台伺服器根目錄磁碟占用空間達到閾值,超過百分之八十了
登上伺服器,df -Th
看一下,發現磁碟空間確實不夠用了
進入到根目錄,然後 du -sh *
可以看到,var 目錄下的磁碟空間已經占用了 75G
既然如此,刪除 var 目錄下一些占空間較大的數據文件即可
![](https://img2023.cnblogs.com/blog/2958925/202303/2958925-20230318081315182-130308807.png)
繼續定位到占用空間較大的是 /var/log 目錄
最後排查到 /var/log/nginx/access_log
這個文件占了 66G
這個文件是 Nginx 產生的訪問日誌文件,從日誌大小來看,一方面沒有做日誌切割,另一方面很久沒有清理這個文件
基本能夠判斷是這個文件造成的告警,執行如下刪除操作
刪除完畢,我們再看下系統磁碟空間
咦?根分區空間怎麼還沒有釋放,不是刪除了文件了嗎?
案例現象
一般來講,很少出現刪除了文件但磁碟空間不釋放的現象
但是如果出現了,就要考慮到以下兩種情況:
-
文件被某一進程鎖定了
-
有進程一直在向這個文件寫數據
為什麼文件被進程占用之後刪除不會釋放磁碟空間呢?
我們來學習一下 Linux 的文件存儲結構
在 Linux 中,文件存儲在硬碟上,硬碟的最小存儲單位是扇區(Sector),然而扇區只有 512位元組大小,如果每次都讀寫這麼小的單位效率一定很低
![](https://img2023.cnblogs.com/blog/2958925/202303/2958925-20230318101755829-751721003.png)
所以當操作系統從硬碟讀取數據的時候,不會一個個扇區的地去讀取,而是一次性連續讀取多個扇區,即一次性讀取一個”塊“(block)
由多個 sector 組成的 block ,是文件存取的最小單位
block 常見大小的是 4KB,即連續 8 個 sector 組成一個 block
![](https://img2023.cnblogs.com/blog/2958925/202303/2958925-20230318101808057-573116667.png)
既然文件數據都存儲在 block 中,那麼我們指定讀取某個文件數據的時候,操作系統就需要知道這個文件存儲在哪個 block 上
而文件的數據存放位置信息被存放到了 inode 上,inode 中文名叫索引節點
我要打開 1.txt 這個文件並讀取內容,會經過以下步驟
1、系統根據文件名(1.txt)找到對應的 inode 號
2、通過 inode 號獲取到 inode 信息
3、根據 inode 信息找到文件數據所在的 block ,讀出數據
除了文件的數據存放信息,文件的創建者、文件的大小、文件的屬性等文件的元信息都被存儲到了 inode 上
文件元信息包含以下內容(可以通過 stat
命令查看)
-
文件的位元組數
-
文件擁有者的 User ID
-
文件擁有者的 User ID
-
文件擁有者的 User ID
-
文件的時間戳
-
鏈接數,即有多少文件名指向這個inode
-
數據block的位置
inode 跟數據一樣會消耗硬碟空間,所以硬碟格式化的時候,系統自動將硬碟分成2個區域:
-
一個是數據區,存放文件數據
-
另一個是 inode 區,存放 inode 所包含的信息,即文件元信息
簡單來說在 Linux 下,文件由指針部分(inode)和數據部分(data)組成
在瞭解了文件的存儲結構之後,我們來看下對文件執 rm 行刪除操作之後,這兩個部分會發生什麼
文件被刪除的時候,文件對應的 inode 就被刪除掉了,而文件的數據部分在 inode 被清除掉之後,就會被覆蓋並寫入新的內容
但是如果文件在刪除的時候是被打開的(有一個進程正在使用該文件,文件被進程鎖定或者有進程一直在向這個文件寫數據等)狀態,那麼進程依舊可以讀取該文件,系統就會認為該文件的磁碟空間一直被占用
之所以出現刪除 access_log 文件後空間沒有釋放,是因為 nginx 進程還在一直向這個文件寫入內容
雖然刪除了 access_log 文件,但是由於 nginx 進程鎖定,文件的 inode 並沒有清除掉,而由於 inode 沒有清除,系統內核就認為文件並未刪除,這才出現空間不釋放的情況
解決問題
既然有了定位的思路,我們就來看看是不是有進程一直在向 access_log 文件寫數據
我們使用 lsof
命令
可以看到 /var/log/nginx/access_log
被進程 nginx 鎖定,而且 nginx 進程一直在往這個文件寫數據,現在文件大小已經 68G 了
由此可見,這個文件就是導致系統根目錄空間耗盡的罪魁禍首,而最後一列的 deleted
狀態表示這個文件已經被刪除
但由於進程還在一直往裡面寫數據,導致磁碟空間並未釋放
-
方法一
刪除掉日誌文件之後,重啟 nginx 進程或者重啟系統讓操作系統來回收磁碟空間
但是在生產環境下一般不建議重啟服務或者重啟系統
萬一齣問題了,這個鍋可背不起
-
方法二(推薦)
像這種進程不停對文件寫數據的操作,如果你想要清空磁碟空間,推薦的辦法是線上清空這個文件
通過這種方法,磁碟空間不僅可以馬上釋放,也可以保證進程能夠一直往文件里寫數據
感謝閱讀,喜歡作者就動動小手[一鍵三連],這是我寫作最大的動力