我有两台服务器(通过互联网的 SSH 访问),其中一台配有高端 CPU 和 32GB RAM。但是,当我尝试通过以下命令压缩大量文件(约 400,000 个)时:
tar cvf archive.tar folder
大约需要 2 个小时。当我在具有类似规格但 RAM 较少的计算机上执行相同的命令时,需要大约 5 分钟才能将一批类似的文件打包成 tar。
有人有什么想法或替代方案吗?命令行输出所有文件的列表。我不知道这是否会导致问题。
答案1
磁盘碎片。如果文件很大,您可以使用它filefrag
来检查单个文件的碎片程度,但还有另一种碎片往往发生在许多小文件中:名称在目录中出现的顺序可能与 inode 在磁盘上出现的顺序完全不同,而该顺序可能与磁盘上数据块的顺序完全不同。这意味着当您按照名称在目录中出现的顺序打开所有文件时,磁盘必须进行大量寻道并降低速度。我曾经编写过以下 python 脚本来计算当前目录中所有文件的名称、inode 和第一个数据块之间的相关性,以便您可以测量这一点:
#!/usr/bin/python
import os
from stat import *
import fcntl
import array
names = os.listdir('.')
lastino = 0
name_to_ino_in = 0
name_to_ino_out = 0
lastblock = 0
name_to_block_in = 0
name_to_block_out = 0
iblocks = list()
inode_to_block_in = 0
inode_to_block_out = 0
for file in names :
try :
st = os.stat(file)
except OSError:
continue
if not S_ISREG(st.st_mode) :
continue
if st.st_ino > lastino :
name_to_ino_in += 1
else : name_to_ino_out += 1
lastino = st.st_ino
f = open(file)
buf = array.array('I', [0])
err = fcntl.ioctl(f.fileno(), 1, buf)
if err != 0 :
print "ioctl failed on " + f
block = buf[0]
if block != 0 :
if block > lastblock :
name_to_block_in += 1
else : name_to_block_out += 1
lastblock = block
iblocks.append((st.st_ino,block))
print "Name to inode correlation: " + str(float(name_to_ino_in) / float((name_to_ino_in + name_to_ino_out)))
print "Name to block correlation: " + str(float(name_to_block_in) / float((name_to_block_in + name_to_block_out)))
iblocks.sort()
lastblock = 0
for i in iblocks:
if i[1] > lastblock:
inode_to_block_in += 1
else: inode_to_block_out += 1
lastblock = i[1]
print "Inode to block correlation: " + str(float(inode_to_block_in) / float((inode_to_block_in + inode_to_block_out)))
旧文件系统在很长一段时间内添加了许多小文件,因此往往会变得很糟糕。简单地复制整个目录可能会使目标变得更好,然后您可以删除原始文件并用副本替换它。然而,导致这种情况的第二个问题是 ext4 的 htree 索引目录功能,该功能用于包含许多文件的目录,以便更快地查找单个文件名,但本质上完全随机化了名称的顺序。您可以检查目录是否使用 htreelsattr -d
并查找I
属性。
dump
我更喜欢使用而不是进行备份的原因之一tar
是,它不受此问题的影响,因为它会按 inode 顺序读取所有文件,而不管名称在目录中出现的顺序如何。但它仍然必须与 inode 竞争以阻止碎片。复制或传递e2defrag
可以帮助解决这个问题。