Acelere la copia de 1000000 archivos pequeños

10

Tengo 1000000 archivos de 4-20 kb en un directorio. Necesito copiar ese directorio. Pero parece que tengo que buscar cada archivo, así que esto lleva bastante tiempo.

¿Hay alguna manera de acelerar esto?

Actualmente estoy pensando que si pudiera obtener los bloques de disco que ocupan estos archivos, podría ordenarlos, fusionar los bloques que estaban cerca (dado que la lectura secuencial a menudo es más rápida que la búsqueda) y leer estos bloques, de modo que estuvieran en la RAM caché (tengo 32 GB de RAM) antes de hacer la copia.

Pero para que eso funcione, necesito una forma de identificar en qué bloques están los archivos.

Estoy usando EXT4 en un dispositivo magnético (es decir, no SSD).

Editar:

Esto debería funcionar pero no:

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'

Al probarlo en un archivo grande, no almacena en caché el archivo.

Edit2:

Aquí hay algunos puntos de referencia. La memoria caché se enjuagó ( echo 3 >/proc/sys/vm/drop_caches) entre cada ejecución. Mediciones realizadas con 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

Entonces, ¿qué podemos aprender de eso?

Parece que ordenar por inodo es una buena idea. Pero parece que el paralelismo múltiple cpaumenta aún más el rendimiento. Vale la pena enfatizar que la fuente foo/es un disco magnético, por lo que esto ataca el mito de que la paralelización de E / S a un solo eje no acelerará la E / S: la paralelización acelera clara y consistentemente la copia aquí.

Ole Tange
fuente
¿Su directorio contiene solo archivos? ¿Está su ubicación de destino en el mismo sistema de archivos?
Joseph R.
¿Para el comando exacto que está utilizando para copiar? ¿Algo así cp -r /mnt/dir1 /mnt/dirdesto algo así cp /mnt/dir1/* /mnt/dirdest?
maxschlepzig
Solo archivos pero no el mismo sistema de archivos: cp -r / mnt / dir1 / mnt2 / dirdest
Ole Tange
por cierto, no creo que ayude si ejecutas accesos al disco duro en paralelo cuando deseas minimizar las búsquedas de disco.
maxschlepzig
Escribí un programa que ordena los archivos por su número de extensión (es más probable que ocurra en el disco) aquí: github.com/nh2/diskorder
nh2

Respuestas:

9

Asumiendo que

  • las entradas devueltas por readdirno están ordenadas por número de inodo
  • leer archivos en orden de inodo reduce el número de operaciones de búsqueda
  • el contenido de la mayoría de los archivos se encuentra en la asignación inicial de 8k (una optimización ext4) que también debería generar menos operaciones de búsqueda

puede intentar acelerar la copia mediante la copia de archivos en orden de inodo.

Eso significa usar algo como esto:

$ cd /mnt/src
$ ls -U -i | sort -k1,1 -n | cut -d' ' -f2- > ~/clist
$ xargs cp -t /mnt2/dst < ~/clist
maxschlepzig
fuente
@mikeserv, ¿qué quieres decir? ls -Uno es suficiente porque no se ordena por números de inodo ... y ¿por qué debería querer -1?
maxschlepzig
@mikeserv, 'en orden de directorio' no es lo mismo que orden de inodo. Si este fuera el caso, no tendría que usar una palabra diferente para esto. Lo que encuentras extraño no es relevante. Incluso lo he probado en un sistema de archivos ext4. Y allí el orden del directorio es de hecho diferente del orden del inodo. -1solo enumera 'un archivo por línea'; no ayuda con las nuevas líneas en los nombres de archivo. Para eso puedes usar find -print0/xargs -O.
maxschlepzig
@mikeserv, ¿de qué estás hablando? Ejemplo de contador: mkdir tmp; cd tmp; touch foo"<RETURN>"bar; lsimprime 'foo? Bar'. A ls -1también imprime 'foo? Bar'. A ls -1 | wc -limprime '2'. A find -lsimprime el nombre del archivo como './foo\nbar'. A cp -i ls -1` x` falla con 'cp: target' x 'no es un directorio'.
maxschlepzig
Maldición, ¡me estás enseñando a izquierda y derecha! -qhace lo que pensé que -1haría! Una vez más, mis disculpas, sin mencionar las gracias.
mikeserv
4

GNU tar, en la paxtradición, maneja enlaces duros por sí mismo.

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

De esa manera solo tiene los dos tarprocesos y no necesita seguir invocando cpuna y otra vez.

mikeserv
fuente
2

De manera similar a la respuesta de @ maxschlepzig , puede analizar la salida de filefragpara ordenar los archivos en el orden en que aparecen sus primeros fragmentos en el 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 con el sedscript anterior , así que asegúrese de realizar una prueba exhaustiva.

De lo contrario, haga lo que haga, filefrag(parte de e2fsprogs) será mucho más rápido de usar que, hdparmya que puede tomar múltiples argumentos de archivo. Solo la sobrecarga de correr hdparm1,000,000 de veces agregará mucha sobrecarga.

Además, probablemente no sería tan difícil escribir un perlscript (o programa C) en un FIEMAP ioctlarchivo para cada archivo, crear una matriz ordenada de los bloques que deberían copiarse y los archivos a los que pertenecen y luego copiar todo en orden por leer el tamaño de cada bloque del archivo correspondiente (tenga cuidado de no quedarse sin descriptores de archivos).

Graeme
fuente
Esto es bueno, vea también home.ifi.uio.no/paalh/publications/files/ipccc09.pdf para un documento que describe el enfoque y muestra una aceleración de ~ 4x tarpara sus archivos.
nh2
1
Envié un correo electrónico a los autores del artículo, preguntándoles si podían publicarlo qtarcomo código abierto; ahora está en github.com/chlunde/qtar
nh2