Acelere a cópia de 1000000 arquivos pequenos

10

Eu tenho 1000000 arquivos de 4-20 kb em um diretório. Eu preciso copiar esse diretório. Mas parece que eu tenho que procurar cada arquivo, então isso leva um bom tempo.

Existe uma maneira de acelerar isso?

Atualmente, estou pensando que, se eu pudesse obter os blocos de disco que esses arquivos ocupam, poderia classificá-los, mesclar os que estavam próximos (considerando que a leitura seqüencial geralmente é mais rápida do que a busca) e ler esses blocos, para que eles estivessem na RAM cache (tenho 32 GB de RAM) antes de fazer a cópia.

Mas, para que isso funcione, preciso de uma maneira de identificar em quais blocos os arquivos estão.

Estou usando EXT4 em um dispositivo magnético (ou seja, não SSD).

Editar:

Isso deve funcionar, mas não:

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'

Ao testá-lo em um arquivo grande, ele não o armazena em cache.

Edit2:

Aqui estão alguns benchmarks. O cache foi liberado ( echo 3 >/proc/sys/vm/drop_caches) entre cada execução. Medições feitas com 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

Então, o que podemos aprender com isso?

Parece que classificar por inode é uma boa ideia. Mas parece que paralelizar múltiplos cpimpulsiona ainda mais o desempenho. Vale ressaltar que a fonte foo/é um disco magnético; portanto, isso ataca o mito de que a E / S paralela a um único eixo não acelera a E / S: a paralelização clara e consistente acelera a cópia aqui.

Ole Tange
fonte
Seu diretório contém apenas arquivos? Seu local de destino está no mesmo sistema de arquivos?
Joseph R.
Para o comando exato que você está usando para copiar? Algo como cp -r /mnt/dir1 /mnt/dirdestou algo parecido cp /mnt/dir1/* /mnt/dirdest?
maxschlepzig
Somente arquivos, mas não o mesmo sistema de arquivos: cp -r / mnt / dir1 / mnt2 / dirdest
Ole Tange
Aliás, acho que não ajuda se você executar acessos ao disco rígido em paralelo quando desejar minimizar as buscas no disco.
precisa saber é o seguinte
Eu escrevi um programa que as ordens de arquivos por seu número de extensão (mais provável que seja a ocorrência no disco) aqui: github.com/nh2/diskorder
NH2

Respostas:

9

Assumindo que

  • as entradas retornadas por readdirnão são classificadas pelo número do inode
  • ler arquivos em ordem de inode reduz o número de operações de busca
  • o conteúdo da maioria dos arquivos está na alocação inicial de 8k (uma otimização ext4) que também deve gerar menos operações de busca

você pode tentar acelerar a cópia via copiar arquivos em ordem de inode.

Isso significa usar algo como isto:

$ cd /mnt/src
$ ls -U -i | sort -k1,1 -n | cut -d' ' -f2- > ~/clist
$ xargs cp -t /mnt2/dst < ~/clist
maxschlepzig
fonte
@mikeserv, o que você quer dizer? ls -Unão é suficiente porque não classifica por números de inode ... e por que devo querer -1?
maxschlepzig
@mikeserv, 'na ordem dos diretórios' não é igual à ordem dos inodes! Se esse fosse o caso, você não precisaria usar uma palavra diferente para isso. O que você acha estranho não é relevante. Eu até testei em um sistema de arquivos ext4. E a ordem dos diretórios é realmente diferente da ordem dos inodes. -1apenas lista 'um arquivo por linha' - não ajuda com novas linhas nos nomes de arquivos. Para isso você pode usar find -print0/xargs -O.
maxschlepzig
@ mikeserv, o que você está falando? Exemplo de contador: mkdir tmp; cd tmp; touch foo"<RETURN>"bar; lsimprime 'foo? Bar'. A ls -1também imprime 'foo? Bar'. A ls -1 | wc -limprime '2'. A find -lsimprime o nome do arquivo como './foo\nbar'. Um cp -i ls -1` x` falha com 'cp: target' x 'não é um diretório'.
maxschlepzig
Droga - você está me ensinando esquerda e direita! -qfaz o que eu pensei que -1faria! Mais uma vez, minhas desculpas - para não mencionar obrigado.
precisa saber é o seguinte
4

O GNU tar- na paxtradição - lida com hardlinks por conta própria.

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

Dessa forma, você só tem os dois tarprocessos e não precisa continuar invocando cprepetidamente.

mikeserv
fonte
2

Da mesma forma que a resposta de @ maxschlepzig , você pode analisar a saída de filefragpara classificar arquivos na ordem em que seus primeiros fragmentos aparecem no disco:

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 com o sedscript acima , portanto, teste-o minuciosamente.

Caso contrário, o que você fizer filefrag(parte de e2fsprogs) será muito mais rápido de usar do hdparmque pode receber vários argumentos de arquivo. Apenas a sobrecarga de executar hdparm1.000.000 de vezes adicionará muita sobrecarga.

Além disso, provavelmente não seria tão difícil escrever um perlscript (ou programa C), para um FIEMAP ioctlarquivo para cada, criar uma matriz classificada dos blocos que devem ser copiados e dos arquivos aos quais pertencem e copiar tudo em ordem, lendo o tamanho de cada bloco no arquivo correspondente (tenha cuidado para não ficar sem os descritores de arquivos).

Graeme
fonte
Isso é legal, consulte também home.ifi.uio.no/paalh/publications/files/ipccc09.pdf para um artigo que descreve a abordagem e mostra uma aceleração de aproximadamente 4x tarpara seus arquivos.
nh2
1
Enviei um e-mail aos autores do artigo, perguntando se eles poderiam ser lançados qtarcomo código aberto; agora é a github.com/chlunde/qtar
NH2