加速复制1000000个小文件

Ole*_*nge 12 filesystems cache

我有百万4-20 KB文件的目录(可以产生类似的这样的文件:seq 10000 | gzip > a; seq 1000000 | parallel --bar 'head -c{=$_=int(rand()*16)+4=}k a > {}'

. 我需要复制那个目录。但似乎我必须为每个文件做一个搜索,所以这需要很长时间。

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

我目前在想,如果我能得到这些文件占用的磁盘块,我可以对它们进行排序,合并接近的块(鉴于顺序读取通常比寻找更快)并读取这些块,以便它们在 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'
Run Code Online (Sandbox Code Playgroud)

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

编辑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
Run Code Online (Sandbox Code Playgroud)

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

似乎按 inode 排序是个好主意。但它似乎cp进一步并行化了多个提升性能。值得强调的是,源foo/是一个磁盘,所以这打破了将 I/O 并行到单个主轴不会加速 I/O 的神话:这里的并行化清晰且一致地加速了复制。

max*_*zig 10

假如说

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

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

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

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


mik*_*erv 5

GNU tar- 按照pax传统 - 自行处理硬链接。

cd "$srcdir" ; tar --hard-dereference -cf - ./* |
    tar -C"${tgtdir}" -vxf -
Run Code Online (Sandbox Code Playgroud)

这样你就只有两个tar进程,你不需要cp一遍又一遍地调用。