2009-10-27 52 views
1

我們在Linux上遇到一個問題,隨着時間的推移,目錄inode變得越來越大,速度越來越慢,因爲創建和刪除了許多文件。例如:Unix目錄inode - 碎片和轉儲目錄內容

% ls -ld foo 
drwxr-xr-x 2 webuser webuser 1562624 Oct 26 18:25 foo 
% time find foo -type f | wc -l 
    518 
real 0m1.777s 
user 0m0.000s 
sys  0m0.010s 

% cp -R foo foo.tmp 
% ls -ld foo.tmp                  
drwxr-xr-x 2 webuser webuser  45056 Oct 26 18:25 foo.tmp 
% time find foo.tmp -type f | wc -l 
    518 
real 0m0.198s 
user 0m0.000s 
sys  0m0.010s 

原始目錄有518個文件,需要1.5 MB來表示,需要1.7秒來遍歷。

重建的目錄具有相同數量的文件,需要45K來表示和.2秒來遍歷。

我想知道會造成這種情況。我的猜測是碎片化 - 一般來說這不應該是Unix文件系統的問題,但在這種情況下,我們使用目錄作爲短期緩存文件,因此不斷創建,重命名和刪除大量小文件。

我也想知道是否有辦法轉儲目錄的文字二進制內容 - 也就是說,讀取目錄就好像它是一個文件 - 這可能會讓我深入瞭解它爲什麼如此之大。無論是閱讀()也沒有從Perl的sysread執行()可以讓我:

swartz> perl -Mautodie -MPOSIX -e 'sysopen(my $fh, "foo", O_RDONLY); my $len = sysread($fh, $buf, 1024);' 
Can't sysread($fh, '', '1024'): Is a directory at -e line 1 

系統信息:

Linux 2.6.18-128.el5PAE #1 SMP Wed Dec 17 12:02:33 EST 2008 i686 i686 i386 GNU/Linux 

謝謝!

喬恩

+0

也許你應該用不同的文件系統進行試驗。嘗試xfs。 – Artelius 2009-10-27 00:24:34

+0

請指定您正在使用的文件系統。 – camh 2009-10-27 03:06:28

回答

2

問題1,外部碎片通常會導致約2倍左右的開銷,再加上你有從分配粒度內部碎片。這些都不能解釋你的觀察。

所以,我不認爲這是正常的穩態碎裂。

最明顯的推測是1.5MB是高水位標記;有一次它確實有1.5MB字節的條目或1.5MB/2字節的條目與預期的碎片。

另一個猜測是50%的規則正在被非馬爾可夫分配所擊敗。想象一下,我用「tmp%d」命名文件,所以,tmp1,tmp2,... tmp1000,tmp1001,...

這裏的問題是rm tmp1沒有爲tmp1001騰出空間。這顯然是一個瘋狂的猜測。

Q2:沒有一種好的方法來讀取原始目錄。 AFAIK,您需要破解內核或使用debugfs來更改inode類型,讀取它,然後將其更改回來,或使用debugfs讀取inode,獲取塊號,然後讀取塊。功能調試方法可能更合理。

您可以通過確保啓用索引來解決性能問題。請參閱tune2fs


Knuth的50%規則:在穩定狀態下,OPS的50%分配,50%的FreeS,空閒塊的50%合併,那麼孔分配的50%和50%的空間被浪費了。 (也就是說,100%的開銷。)這被認爲是「正常的」。 Malloc也有同樣的問題。

+0

很好的答案,謝謝。我們在一個時間點上暫時增加了#個文件,所以你的「顯而易見的推測」有一些優點(並且不幸的是,直到你指出它的時候,這對我來說並不明顯)。) – 2009-10-28 12:16:09

0

由於重複創建和刪除文件而導致碎片。隨着inode大小的增加,它不會再次縮小,因此即使大部分都是空的,它仍然很大。

我覺得你有主要有兩種措施來應對這個問題:

  1. 建立一個子目錄結構,以防止過多的孩子在一個單獨的目錄的父。例如,如果您正在創建其路徑格式爲dir/file-%06d的文件,那麼您正在使其擁有一百萬個擁有其預期大型目錄索引節點的子節點。您寧願設計一些將文件名分解成其變量前綴的子樹結構,例如,如果您的文件是file-123456.ext,則將它們分配到dir/files/1/2/3/4/123456.ext之類的東西中。這個策略將限制在最終目錄葉子下的最大兒童數量爲1000。分解級別取決於文件名的變量部分的大小。作爲一種對策,一旦你已經擁有巨大的目錄inode,除了創建一個新的(小inode)兄弟目錄,將所有的原始文件(。)移動到新的目錄之外,還有其他的工作要做,刪除原始目錄並將新目錄重命名爲原始名稱。注意在原始路徑下同時運行服務。

涉及目錄上findstat --printf='%b'%s一些shell-FU可以幫助你檢測其他麻煩點到你的文件系統,並把他們下仔細觀察。

對於具體的文件系統的細節,look at this post in ServerFault.com