1,000,000個の小さなファイルコピー速度を向上

1,000,000個の小さなファイルコピー速度を向上

私のディレクトリには1000,000個の4-20kbファイルがあります(これに似たファイルを作成できますseq 10000 | gzip > a; seq 1000000 | parallel --bar 'head -c{=$_=int(rand()*16)+4=}k a > {}':)

。このディレクトリをコピーする必要があります。ところで、ファイルを毎日検索しなければならないようで、時間がかなりかかります。

スピードを上げる方法はありますか?

現在、これらのファイルが占めるディスクブロックを取得できる場合は、ファイルを並べ替えて近いブロックをマージし(シーケンシャル読み出しが通常ナビゲーションより高速であることを考慮して)、ブロックを読み取ってRAMキャッシュに含めることができると考えています。コピー(私は32GBの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速度が速くならないという通念が壊れました。ここで明示的かつ一貫して並列化すると、レプリケーションが速くなる可能性があります。

答え1

私たちが言うと

  • 返された項目はreaddirinode 番号でソートされません。
  • inode順にファイルを読み取ると、検索操作の数が減ります。
  • ファイルの内容のほとんどは初期の8k割り当て(ext4最適化)内にあるため、ナビゲーション操作も削減されます。

inode の順番でファイルをコピーしてコピー速度を上げることができます。

これは、次のようなものを使用することを意味します。

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

答え2

tar伝統的に、GNUはpaxハードリンク自体を処理します。

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

これにより、2つのプロセスがあり、繰り返し呼び出すtar必要がなくなります。cp

答え3

同様に寄稿者: @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

MMVには上記のスクリプトが含まれていますので、sed徹底的にテストしてください。

そうでなければ、何をしても(の一部)は、複数のファイル引数を使用できるよりもはるかに速くfilefrag使用されます。 1,000,000回実行するオーバーヘッドだけでも多くのオーバーヘッドが追加されます。e2fsprogshdparmhdparm

perlまたFIEMAP ioctl、各ファイルに対してコピーするチャンクとそのチャンクが属するファイルの整列配列を作成し、すべてを順番にコピーして各チャンクを読み取るスクリプト(またはCプログラム)を作成することはそれほど難しくありません。そのファイルサイズ(ただし、ファイル記述子が不足しないように注意してください)

関連情報