關於“No space left on device的原因”

anycall2010發表於2008-06-30
看到這個錯誤,第一個反應是磁碟空間滿了;但 df 一看,每個分割槽的空間都還富餘的很。從 munin 的監控圖表上看 Filesystem usage 也很平穩,但下面的 Inode usage 就有問題了,其中一個分割槽的 usage 已經到了100%。趕緊跑到伺服器上 df -i 檢查,果然是 Inode 耗盡。原來這個分割槽是用來扔各種日誌和臨時檔案的,其中有某個程式產生的臨時檔案又小又多,又沒有進行定時回滾,造成在磁碟空間耗盡之前檔案系統的 Inode 就被用光了。

  Linux/Unix like OS 的檔案系統中每個目錄樹中的節點並不是像 Windows 那樣直接包含檔案的具體資訊,而只包含了檔名和 Inode number 。通過 Inode number 所找到對應於檔名的 Inode 節點中才真正記錄了檔案的大小/實體地址/所有者/訪問許可權/時間戳/被硬連結的次數等實際的 metadata 。因此你可以在 Linux 系統中通過硬連結( hard link ) 的方式給某個檔案建立無數個位於不同目錄下的檔名,而實際的檔案資料只需要一份拷貝。

  但也正因為這種檔案系統的結構,當你在 Linux 中進行 IO 操作的時候,需要的資源除了磁碟空間以外,還要有剩餘的 Inode 才行。預設情況下, Linux 在系統安裝過程中按照1個 Inode 對應 2k 磁碟空間來計算每個分割槽的最大 Inode 數。一旦檔案系統建立之後,每個分割槽可用 Inode 數就無法進行動態調整。

  正常來說,一般不太會出現某個分割槽的 Inode 耗盡而磁碟空間尚餘的情況,除非像我碰到的這樣垃圾小檔案瘋長而又沒進行有效的清理。但如果確實需要的話,可以在建立檔案系統(比如用 mke2fs )的時候根據實際需要來調整這個引數(比如分割槽如果用於存放超大視訊檔案的話 Inode 的數量可以少一些;如果打算存放的檔案是大量小於 2k 的迷你檔案的話就要考慮多建立一些 Inode)。

No space left on device 原因:

  超出系統中同時執行的最大 message queue 個數限制 : 在 root 下用 sysctl kernel.msgmni 檢查該引數, sysctl -w kernel.msgmni=XXX 重新設定即可。

附錄一則:“比較罕見的一個問題,磁碟檔案數目太多導致的LISTENER監聽起不來”解決方法:[轉載]

問題提出:
一臺測試的伺服器,停電再起來後發現listener起不來,報錯如下:
Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.191.100)(PORT=1521)))
Error listening on: (ADDRESS=(PROTOCOL=ipc)(PARTIAL=yes)(QUEUESIZE=1))
No longer listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.191.100)(PORT=1521)))
TNS-12549: TNSperating system resource quota exceeded
TNS-12560: TNSrotocol adapter error
TNS-00519: Operating system resource quota exceeded
Linux Error: 28: No space left on device


 

首先檢視log檔案,已經2G了,開啟看看日誌裡面也沒發現什麼異常,認為日誌是自然增長到這麼大的,於是直接cat /dev/null>listener.log把日誌清空。然後listener還是起不來,仍然報上面的錯誤。之後重啟機器,還是不行,檢查磁碟空間:
oracle@test-db1 admin]$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sdb2 4.9G 1.9G 2.7G 42% /
/dev/sdb1 99M 15M 79M 16% /boot
/dev/sdb7 1012M 493M 468M 52% /home
/dev/sdb8 61G 41G 18G 71% /opt
none 1000M 0 1000M 0% /dev/shm
/dev/sdb5 2.0G 33M 1.9G 2% /tmp
/dev/sdb6 1012M 606M 355M 64% /var
/dev/sda1 34G 14G 19G 43% /
oracle安裝在/opt目錄,上面還有18個G的空間,而且每個磁碟空間都很多。檢視process限制,top發現系統才開了50個process,而對oracle的限制是2048個。在pub的發帖,地址如下:
http://www.itpub.net/showthread.php?s=&threadid=809058&perpage=10&pagenumber=1
一直沒有解決,後來通知同事有這個問題存在。週一上班,同事說這個問題已經被他解決了,並推薦一篇文章給我,地址如下:
http://www.zeali.net/entry/480
摘錄一部分:
Linux/Unix like OS 的檔案系統中每個目錄樹中的節點並不是像 Windows 那樣直接包含檔案的具體資訊,而只包含了檔名和 Inode number 。通過 Inode number 所找到對應於檔名的 Inode 節點中才真正記錄了檔案的大小/實體地址/所有者/訪問許可權/時間戳/被硬連結的次數等實際的 metadata 。因此你可以在 Linux 系統中通過硬連結( hard link ) 的方式給某個檔案建立無數個位於不同目錄下的檔名,而實際的檔案資料只需要一份拷貝。但也正因為這種檔案系統的結構,當你在 Linux 中進行 IO 操作的時候,需要的資源除了磁碟空間以外,還要有剩餘的 Inode 才行。預設情況下, Linux 在系統安裝過程中按照1個 Inode 對應 2k 磁碟空間來計算每個分割槽的最大 Inode 數。一旦檔案系統建立之後,每個分割槽可用 Inode 數就無法進行動態調整。正常來說,一般不太會出現某個分割槽的 Inode 耗盡而磁碟空間尚餘的情況,除非像我碰到的這樣垃圾小檔案瘋長而又沒進行有效的清理。但如果確實需要的話,可以在建立檔案系統(比如用 mke2fs )的時候根據實際需要來調整這個引數(比如分割槽如果用於存放超大視訊檔案的話 Inode 的數量可以少一些;如果打算存放的檔案是大量小於 2k 的迷你檔案的話就要考慮多建立一些 Inode)。
使用df -i命令可以看到每個分割槽的總inode數目和被使用的以及空閒的inode數目:
[root@test-db1 log]# df -i
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/sdb2 640000 115018 524982 18% /
/dev/sdb1 26104 40 26064 1% /boot
/dev/sdb7 131616 409 131207 1% /home
/dev/sdb8 8077312 168316 7908996 3% /opt
none 255900 1 255899 1% /dev/shm
/dev/sdb5 262144 182 261962 1% /tmp
/dev/sdb6 131616 1500 130116 2% /var
/dev/sda1 4447744 117 4447627 1% /u01
上面的結果是同事已經處理後的結果,原因是/var的一個子目錄下產生很多很小的檔案,刪除後恢復正常,listener可以正常起來了。
繼續做下面一個試驗:
首先找到一個大小為200多k的測試檔案
[root@localhost test]# ll
total 208
-rw-r--r-- 1 root root 206305 Mar 8 10:28 test.log
然後檢視/usr的inode使用情況
[root@localhost test]# df -i
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/sda6 525888 98096 427792 19% /usr
然後把test.log分割成每個位元組一個檔案,split的使用方法可以參考:http://zhang41082.itpub.net/post/7167/289531
[root@localhost test]# split -a 10 -b 1 test.log
統計分割後的總檔案數目,比test.log的檔案大小206305多了兩個,這個一個是因為test.log檔案本身佔一個,還有就是統計的返回結果佔一行,所以看到檔案被成功分割為206305個。
[root@localhost test]# ll | wc -l
206307
檢視inode使用情況
[root@localhost test]# df -i
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/sda6 525888 304401 221487 58% /usr
可以看到,inode增加了304401-98096=206305個。然後把test.log重新命名為test1.log,重新分裂
[root@localhost test]# split -a 10 -b 1 test1.log z
[root@localhost test]# ll|wc -l
412612
[root@localhost test]# df -i
Filesystem Inodes IUsed IFree IUse% Mounted on
/dev/sda6 525888 510706 15182 98% /usr
inode已經使用了98%了,再重複一次
[root@localhost test]# mv test1.log test2.log
[root@localhost test]# split -a 10 -b 1 test2.log y
split: yaaaaaaawly: No space left on device
可以看到,進行到一半的時候已經不能對檔案再進行分割了,而錯誤提示也已經出現 No space left on device。

總結:這類錯誤是比較少見的錯誤,有時候oracle的bug或者其他原因會導致某個目錄的trace檔案數目瘋長,這時候就要小心這個問題了,因此日常的系統監控除了要監控磁碟空間的大小,對inode的使用情況也應該進行監控。
從這個問題可以看出,作業系統的知識多麼重要,感謝zeal的文章,感謝同事提供了這篇文章。

後續和補充:

今天看到pub上eygle給出了更合理的解釋,放在這裡作為補充。

為什麼/var目錄的inode滿了會影響到裝在/opt目錄的oracle不能啟動呢?原來listener啟動的時候會在/var/tmp目錄下的.oracle隱藏目錄下建立兩個臨時檔案:

[oracle@stream .oracle]$ ll
total 0
srwxrwxrwx 1 oracle oinstall 0 Feb 5 05:49 s#4036.1
srwxrwxrwx 1 oracle oinstall 0 Feb 5 05:49 s#4036.2
srwxrwxrwx 1 oracle oinstall 0 Apr 20 04:26 s#5332.1
srwxrwxrwx 1 oracle oinstall 0 Apr 20 04:26 s#5332.2
srwxrwxrwx 1 oracle oinstall 0 Jan 22 21:53 s#7306.1
srwxrwxrwx 1 oracle oinstall 0 Jan 22 21:53 s#7306.2
srwxrwxrwx 1 oracle oinstall 0 Jan 13 04:21 s#9611.1
srwxrwxrwx 1 oracle oinstall 0 Jan 13 04:21 s#9611.2

可以看到這個臨時檔案確實是成對出現的。

<!-- comment these out if you want to see an example of custom fields, but remember to name the fields in the same way they are named here: 'imfeeling' (livejournal.com style), 'listening' and 'new_field'

: ?

最新回覆

EYGLE的trace檔案中很明顯,execve("/opt/oracle/product/9.2.0/bin/lsnrctl", ["lsnrctl", "start"], [/* 33 vars */]) = 0
connect(4, {sa_family=AF_UNIX, path="/var/run/.nscd_socket"}, 110) = -1 ENOENT (No such file or directory)
access("/var/tmp/.oracle", F_OK) = 0
access("/var/tmp/.oracle/sEXTPROC", F_OK) = 0
connect(4, {sa_family=AF_UNIX, path="/var/tmp/.oracle/sEXTPROC"}, 110) = 0
如果檔案建立不了,導致不能繼續執行下面的操作了,猜測,當時如果用strace做跟蹤,你的access("/var/tmp/.oracle", F_OK) = 0
狀態可能不是0了(0可能代表的是兩個臨時檔案建立成功),呵呵!

 

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8334342/viewspace-366422/,如需轉載,請註明出處,否則將追究法律責任。

相關文章