Accélérez la copie de 1000000 petits fichiers

11

J'ai 1000000 fichiers de 4-20 ko dans un répertoire. J'ai besoin de copier ce répertoire. Mais il semble que je doive faire une recherche pour chaque fichier, donc cela prend un certain temps.

Existe-t-il un moyen d’accélérer cela?

Je pense actuellement que si je pouvais obtenir les blocs de disque que ces fichiers occupent, je pourrais les trier, fusionner les blocs qui étaient proches (étant donné que la lecture séquentielle est souvent plus rapide que la recherche) et lire ces blocs, afin qu'ils soient en RAM cache (j'ai 32 Go de RAM) avant de faire la copie.

Mais pour que cela fonctionne, j'ai besoin d'un moyen d'identifier les blocs sur lesquels se trouvent les fichiers.

J'utilise EXT4 sur un appareil magnétique (c'est-à-dire pas SSD).

Éditer:

Cela devrait fonctionner mais cela ne:

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'

Lorsque vous le testez sur un gros fichier, il ne met pas le fichier en cache.

Edit2:

Voici quelques repères. Le cache a été vidé ( echo 3 >/proc/sys/vm/drop_caches) entre chaque exécution. Mesures effectuées avec 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

Que pouvons-nous en tirer?

Il semble que le tri par inode soit une bonne idée. Mais il semble que la parallélisation de plusieurs cpboosts de performances soit encore plus poussée. Il convient de souligner que la source foo/est un disque magnétique, donc cela attaque le mythe selon lequel la parallélisation des E / S à une seule broche n'accélérera pas les E / S: la parallélisation accélère clairement et systématiquement la copie ici.

Ole Tange
la source
Votre répertoire contient-il uniquement des fichiers? Votre emplacement cible est-il sur le même système de fichiers?
Joseph R.
Pour la commande exacte que vous utilisez pour la copie? Quelque chose comme cp -r /mnt/dir1 /mnt/dirdestou quelque chose comme cp /mnt/dir1/* /mnt/dirdest?
maxschlepzig
Seuls les fichiers mais pas le même système de fichiers: cp -r / mnt / dir1 / mnt2 / dirdest
Ole Tange
btw, je ne pense pas que cela aide si vous exécutez des accès au disque dur en parallèle lorsque vous voulez minimiser les recherches de disque.
maxschlepzig
J'ai écrit un programme qui commande les fichiers par leur numéro d'extension (plus susceptible d'être l'occurrence sur le disque) ici: github.com/nh2/diskorder
nh2

Réponses:

9

En admettant que

  • les entrées retournées par readdirne sont pas triées par numéro d'inode
  • la lecture des fichiers dans l'ordre des inodes réduit le nombre d'opérations de recherche
  • le contenu de la plupart des fichiers se trouve dans l'allocation initiale de 8 Ko (une optimisation ext4) qui devrait également générer moins d'opérations de recherche

vous pouvez essayer d'accélérer la copie en copiant les fichiers dans l'ordre des inodes.

Cela signifie utiliser quelque chose comme ça:

$ cd /mnt/src
$ ls -U -i | sort -k1,1 -n | cut -d' ' -f2- > ~/clist
$ xargs cp -t /mnt2/dst < ~/clist
maxschlepzig
la source
@mikeserv, que voulez-vous dire? ls -Un'est pas suffisant car il ne trie pas par numéro d'inode ... et pourquoi devrais-je le vouloir -1?
maxschlepzig
@mikeserv, 'dans l'ordre des répertoires' n'est pas la même chose que dans l'ordre des inodes! Si tel était le cas, vous n'auriez pas à utiliser un mot différent pour cela. Ce que vous trouvez étrange n'est pas pertinent. Je l'ai même testé sur un système de fichiers ext4. Et là, l'ordre des répertoires est en effet différent de l'ordre des inodes. -1répertorie simplement «un fichier par ligne» - cela n'aide pas avec les retours à la ligne dans les noms de fichiers. Pour cela, vous pouvez utiliser find -print0/xargs -O.
maxschlepzig
@mikeserv, de quoi tu parles? Exemple de compteur: mkdir tmp; cd tmp; touch foo"<RETURN>"bar; lsimprime 'foo? Bar'. A ls -1imprime également 'foo? Bar'. A ls -1 | wc -limprime «2». A find -lsimprime le nom de fichier sous la forme './foo\nbar'. Un cp -i ls -1` x` échoue avec 'cp: la cible' x 'n'est pas un répertoire'.
maxschlepzig
Merde - tu m'apprends à gauche et à droite! -qfait ce que je pensais -1! Encore une fois, mes excuses - sans parler des remerciements.
mikeserv
4

GNU tar- dans la paxtradition - gère seul les liens physiques.

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

De cette façon, vous n'avez que les deux tarprocessus et vous n'avez pas besoin de continuer à invoquer cpencore et encore.

mikeserv
la source
2

Dans la même veine que la réponse de @ maxschlepzig , vous pouvez analyser la sortie de filefragpour trier les fichiers dans l'ordre dans lequel leurs premiers fragments apparaissent sur le disque:

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 avec le sedscript ci-dessus , alors assurez-vous de tester soigneusement.

Sinon, quoi que vous fassiez, filefrag(une partie de e2fsprogs) sera beaucoup plus rapide à utiliser hdparmqu'il ne peut prendre plusieurs arguments de fichier. Le simple fait de courir hdparm1 000 000 fois va ajouter beaucoup de frais généraux.

De plus, il ne serait probablement pas si difficile d'écrire un perlscript (ou un programme C) dans un FIEMAP ioctlfichier pour chaque fichier, de créer un tableau trié des blocs qui devraient être copiés et des fichiers auxquels ils appartiennent, puis de tout copier dans l'ordre en lire la taille de chaque bloc à partir du fichier correspondant (attention cependant à ne pas manquer de descripteurs de fichiers).

Graeme
la source
C'est bien, voir aussi home.ifi.uio.no/paalh/publications/files/ipccc09.pdf pour un article qui décrit l'approche et montre une accélération de ~ 4x tarpour leurs fichiers.
nh2
1
J'ai envoyé un courriel aux auteurs du document, leur demandant s'ils pouvaient publier qtaren open source; c'est maintenant sur github.com/chlunde/qtar
nh2