加快复制1000000个小文件的速度


11

我的目录中有1000000个4-20 KB文件。我需要复制该目录。但是似乎我必须对每个文件进行搜索,因此这需要花费相当长的时间。

有什么方法可以加快速度吗?

我目前在想,如果我可以获取这些文件所占用的磁盘块,则可以对它们进行排序,合并关闭的块(假设顺序读取通常比查找要快)并读取这些块,以便它们位于RAM中缓存(我有32 GB RAM),然后再进行复制。

但是,要使其正常工作,我需要一种方法来确定文件位于哪些块上。

我在磁性设备(即非SSD)上使用EXT4。

编辑:

这应该可行,但不能:

ls |
parallel -IOO --pipe "sudo parallel -j100 hdparm --fibmap {}'|tail -n +5'" |
sort -nk 2 | 
perl -ane 'if($u+10000 < $F[1]) { print "$l ",($u-$l),"\n"; $l=$F[1] } $u=$F[2]' |
sudo parallel --colsep ' ' dd if=/dev/sda1 skip={1} bs=512 count={2} '| cat >/dev/null'

在大文件上进行测试时,它不会缓存文件。

编辑2:

这是一些基准。echo 3 >/proc/sys/vm/drop_caches在每次运行之间刷新缓存()。用进行的测量iostats -dkx 5

rsync -Hav foo/ bar/: 1800 KB/s
cp -a foo/ bar/: 3600 KB/s
cat sort-by-inode | parallel -j1 -X cp foo/{} bar/: 5000 KB/s
cat sort-by-inode | shuf | parallel -j1 -X cp foo/{} bar/: 3000 KB/s
cat sort-by-inode | shuf | parallel -j10 -X cp foo/{} bar/: 7000 KB/s
cat sort-by-inode | parallel -j10 -X cp foo/{} bar/: 8000 KB/s
cat sort-by-inode | parallel -j100 -X cp foo/{} bar/: 9000 KB/s
cat sort-by-inode | parallel -j500 -X cp foo/{} bar/: 10000 KB/s

那么我们可以从中学到什么呢?

看来按inode排序是个好主意。但是,似乎可以将多个并行cp提升性能进一步提高。值得强调的是,源foo/是磁盘,因此这打破了将I / O并行化为单个主轴不会加速I / O的神话:清晰并行地并一贯地加快此处的复制速度。


您的目录仅包含文件吗?您的目标位置是否在同一文件系统上?
Joseph R.

要获取用于复制的确切命令?诸如此类的cp -r /mnt/dir1 /mnt/dirdest东西cp /mnt/dir1/* /mnt/dirdest
maxschlepzig

仅文件但不相同的文件系统:cp -r / mnt / dir1 / mnt2 / dirdest
Ole Tange

顺便说一句,如果您想最大程度地减少磁盘寻道,那么如果您并行执行硬盘访问不会对您有帮助。
maxschlepzig 2014年

我编写了一个程序,该程序按其扩展区号
nh2

Answers:


9

假如说

  • 返回的条目readdir未按索引节点编号排序
  • 以inode顺序读取文件减少了查找操作的次数
  • 大多数文件的内容在最初的8k分配中(ext4优化),这也应该产生较少的查找操作

您可以尝试通过按inode顺序复制文件来加快复制速度。

那意味着使用这样的东西:

$ cd /mnt/src
$ ls -U -i | sort -k1,1 -n | cut -d' ' -f2- > ~/clist
$ xargs cp -t /mnt2/dst < ~/clist

@mikeserv,你是什么意思?ls -U还不够,因为它不能按索引节点号排序...为什么我要-1
maxschlepzig 2014年

@mikeserv,“按目录顺序”与inode顺序不同!如果是这种情况,则无需为此使用其他单词。您发现的陌生无关紧要。我什至在ext4文件系统上进行了测试。而且目录的顺序确实与inode的顺序不同。-1仅列出“每行一个文件”-它对文件名中的换行符没有帮助。为此,您可以使用find -print0/xargs -O
maxschlepzig 2014年

@mikeserv,您在说什么?反例:显示mkdir tmp; cd tmp; touch foo"<RETURN>"bar; ls“ foo?bar”。A ls -1还显示“ foo?bar”。甲ls -1 | wc -l打印“2”。A find -ls将文件名打印为“ ./foo\nbar”。甲cp -i LS -1` x`失败“CP:目标‘X’不是目录”。
maxschlepzig 2014年

该死的-你在左右教我!-q做到了我想的-1那样!再次致歉-更不用说了。
mikeserv

4

GNU tar-在pax传统-把手硬链接自身。

cd "$srcdir" ; tar --hard-dereference -cf - ./* |
    tar -C"${tgtdir}" -vxf -

这样,您只有两个tar过程,而无需cp一遍又一遍地调用。


2

@maxschlepzig的回答类似,您可以解析filefrag文件的输出,以使它们的第一个片段出现在磁盘上的顺序排序:

find . -maxdepth 1 -type f |
  xargs -d'\n' filefrag -v |
  sed -n '
    /^   0:        0../ {
      s/^.\{28\}\([0-9][0-9]*\).*/\1/
      h
      }
    / found$/ {
      s/:[^:]*$//
      H
      g
      s/\n/ /p
      }' |
    sort -nk 1,1 |
    cut -d' ' -f 2- |
    cpio -p dest_dir

使用上述sed脚本的MMV ,因此请务必进行彻底测试。

否则,无论您做什么,filefrag(的一部分e2fsprogs)都将比使用hdparm多个文件参数要快得多。运行hdparm1,000,000次的开销只会增加很多开销。

同样perlFIEMAP ioctl为每个文件编写一个脚本(或C程序),为每个文件创建一个应该复制的块和文件所属的排序数组,然后按顺序复制所有内容,可能并不难从相应的文件中读取每个块的大小(但是请注意不要耗尽文件描述符)。


这很好,另请参阅home.ifi.uio.no/paalh/publications/files/ipccc09.pdf,以获取描述该方法并显示tar其文件加速4倍的论文。
nh2

1
我已经给论文的作者发了电子邮件,问他们是否可以qtar作为开源发布。现在位于github.com/chlunde/qtar
nh2
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.