我们在Linux上遇到问题,目录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的read()和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 :(得分:2)
对于问题1,外部碎片通常会导致大约2倍左右的开销, 1 以及分配粒度的内部碎片。这些都不能解释你的观察结果。
所以,我不认为这是正常的稳态碎片。
最明显的猜测是1.5MB是高水位;有一段时间它确实有1.5MB字节的条目或1.5MB / 2字节的条目与预期的碎片。
另一种猜测是50%的规则被非马尔可夫分配击败。想象一下,我用“tmp%d”命名文件,因此,tmp1,tmp2,... tmp1000,tmp1001,......
这里的问题是rm tmp1
没有为tmp1001
腾出空间。这显然是一个疯狂的猜测。
Q2:没有一种好方法可以读取原始目录。 AFAIK,您需要破解内核或使用debugfs更改inode类型,读取它,然后将其更改回来,或使用debugfs读取inode,获取块编号,然后读取块。功能调试方法可能更合理。
您可以通过确保启用索引来解决性能问题。请参阅tune2fs
。
1 Knuth的百分之五十的规则:在稳定状态下,50%的操作是分配,50%是自由,50%的空闲块合并,然后漏洞是50%的分配,50空间的百分比被浪费了。 (Aka,100%开销。)这被认为是“正常的”。 Malloc也有同样的问题。
答案 1 :(得分:0)
这是因为重复文件创建和删除造成的碎片。随着inode大小的增加,它永远不会再缩小,所以即使大部分都是空的,它也会保持很大。
我认为你主要有两种措施来解决这个问题:
构建子目录结构,以防止在单个目录parent下有太多子项。例如,如果要创建路径格式为dir/file-%06d
的文件,那么您将使其拥有一百万个具有预期的巨大目录inode的子项。您宁愿设计一些子树结构,将文件名分解为其变量前缀,例如,如果您的文件是file-123456.ext
,则在dir/files/1/2/3/4/123456.ext
之类的内容下分配它们。此策略将最终目录叶下的最大子项数限制为1000。分解的级别取决于文件名的可变部分的大小。
作为对策,一旦你已经拥有庞大的目录inode,除了创建一个新的(小节点)兄弟目录,将所有原始(。)文件移动到新目录之外别无其他,删除原始目录并将新目录重命名为原始名称。注意在原始路径下同时运行服务。
在目录中涉及find
和stat --printf='%b'
或%s
的一些shell-fu可以帮助您检测文件系统中的其他麻烦点,并将它们置于密切观察之中。
有关特定文件系统的详细信息,请look at this post in ServerFault.com