Nos gustaría almacenar millones de archivos de texto en un sistema de archivos Linux, con el propósito de poder comprimir y servir una colección arbitraria como servicio. Hemos probado otras soluciones, como una base de datos clave / valor, pero nuestros requisitos de concurrencia y paralelismo hacen que el uso del sistema de archivos nativo sea la mejor opción.
La forma más directa es almacenar todos los archivos en una carpeta:
$ ls text_files/
1.txt
2.txt
3.txt
que debería ser posible en un sistema de archivos EXT4 , que no tiene límite para la cantidad de archivos en una carpeta.
Los dos procesos de FS serán:
- Escribir un archivo de texto desde el web scrape (no debería verse afectado por la cantidad de archivos en la carpeta).
- Comprima los archivos seleccionados, dados por la lista de nombres de archivos.
Mi pregunta es: ¿el almacenamiento de hasta diez millones de archivos en una carpeta afectará el rendimiento de las operaciones anteriores, o el rendimiento general del sistema, de manera diferente a hacer un árbol de subcarpetas para que vivan los archivos?
fuente
dir_index
, que a menudo está habilitado de forma predeterminada, acelerará las búsquedas, pero puede limitar la cantidad de archivos por directorio.ls -l
o cualquier otra cosa que seastat
cada inodo en el directorio (por ejemplo,bash
finalización de pestañas / tabulación) será artificialmente más rápido que después de un poco de desgaste (borre algunos archivos, escriba algunos nuevos). ext4 podría funcionar mejor con esto que XFS, porque XFS asigna dinámicamente espacio para inodes frente a datos, por lo que puede terminar con inodos más dispersos, creo. (Pero esa es una suposición pura basada en muy poco conocimiento detallado; apenas he usado ext4). Ir conabc/def/
subdirs.ZipOutputStream
superaría a casi cualquier sistema de archivos nativo de Linux gratuito. Dudo que quiera pagar por el GPFS de IBM. El ciclo para procesar un conjunto de resultados JDBC y hacer que la secuencia zip sea probablemente solo de 6 a 8 líneas de código Java.Respuestas:
El
ls
comando, o incluso la finalización de TAB o la expansión de comodín por parte del shell, normalmente presentará sus resultados en orden alfanumérico. Esto requiere leer el listado completo del directorio y ordenarlo. Con diez millones de archivos en un solo directorio, esta operación de clasificación tomará una cantidad de tiempo no despreciable.Si puede resistir el impulso de completar TAB y, por ejemplo, escribir los nombres de los archivos que se van a comprimir por completo, no debería haber problemas.
Otro problema con los comodines podría ser la expansión de comodines que posiblemente produzca más nombres de archivo de los que caben en una línea de comando de longitud máxima. La longitud máxima típica de la línea de comandos será más que adecuada para la mayoría de las situaciones, pero cuando hablamos de millones de archivos en un solo directorio, esto ya no es una suposición segura. Cuando se excede la longitud máxima de la línea de comando en la expansión de comodines, la mayoría de los shells simplemente fallarán en toda la línea de comando sin ejecutarla.
Esto se puede resolver haciendo sus operaciones comodín con el
find
comando:o una sintaxis similar siempre que sea posible. El
find ... -exec ... \+
automáticamente tomará en cuenta la longitud máxima de la línea de comando, y ejecutará el comando tantas veces como sea necesario mientras ajusta la cantidad máxima de nombres de archivo a cada línea de comando.fuente
ls
comando no sabrán que la lista de directorios ya está ordenada, de todos modos se tomarán el tiempo para ejecutar el algoritmo de ordenación. Y además, el espacio de usuario puede estar usando un orden de clasificación localizado (LC_COLLATE) que puede ser diferente de lo que el sistema de archivos podría hacer internamente.Esto está peligrosamente cerca de una pregunta / respuesta basada en la opinión, pero intentaré proporcionar algunos hechos con mis opiniones.
mv * /somewhere/else
) puede fallar al expandir el comodín con éxito, o el resultado puede ser demasiado grande para usar.ls
llevará más tiempo enumerar una gran cantidad de archivos que una pequeña cantidad de archivos.Una recomendación es dividir el nombre del archivo en fragmentos de dos, tres o cuatro caracteres y usarlos como subdirectorios. Por ejemplo,
somefilename.txt
podría almacenarse comosom/efi/somefilename.txt
. Si está utilizando nombres numéricos, divídalos de derecha a izquierda en lugar de izquierda a derecha para que haya una distribución más uniforme. Por ejemplo,12345.txt
podría almacenarse como345/12/12345.txt
.Puede usar el equivalente de
zip -j zipfile.zip path1/file1 path2/file2 ...
para evitar incluir las rutas intermedias del subdirectorio en el archivo ZIP.Si está sirviendo estos archivos desde un servidor web (no estoy completamente seguro de si eso es relevante) es trivial ocultar esta estructura a favor de un directorio virtual con reglas de reescritura en Apache2. Supongo que lo mismo es cierto para Nginx.
fuente
*
expansión tendrá éxito a menos que se quede sin memoria, pero a menos que aumente el límite de tamaño de pila (en Linux) o use un shell dondemv
está integrado o puede estar integrado (ksh93, zsh), laexecve()
llamada al sistema puede fallar con un error E2BIG.zip -j - ...
y canalizar el flujo de salida directamente a la conexión de red del clientezip -j zipfile.zip ...
. Escribir un archivo zip real en el disco significa que la ruta de datos se lee desde el disco-> comprimir-> escribir en el disco-> leer desde el disco-> enviar al cliente. Eso puede triplicar los requisitos de E / S del disco sobre la lectura desde el disco-> comprimir-> enviar al cliente.Dirijo un sitio web que maneja una base de datos para películas, TV y videojuegos. Para cada uno de estos, hay varias imágenes con TV que contienen docenas de imágenes por programa (es decir, instantáneas de episodios, etc.).
Termina siendo una gran cantidad de archivos de imagen. En algún lugar en el rango de más de 250,000. Todos estos se almacenan en un dispositivo de almacenamiento en bloque montado donde el tiempo de acceso es razonable.
Mi primer intento de almacenar las imágenes fue en una sola carpeta como
/mnt/images/UUID.jpg
Me encontré con los siguientes desafíos.
ls
a través de una terminal remota simplemente se colgaría. El proceso se volvería zombie yCTRL+C
no lo rompería.ls
comando llenaría rápidamente el búfer de salida yCTRL+C
no detendría el desplazamiento sin fin.Terminé teniendo que almacenar los archivos en subcarpetas usando el tiempo de creación para crear la ruta. Tales como
/mnt/images/YYYY/MM/DD/UUID.jpg
. Esto resolvió todos los problemas anteriores y me permitió crear archivos zip que apuntaban a una fecha.Si el único identificador para un archivo que tiene es un número numérico, y estos números tienden a ejecutarse en secuencia. ¿Por qué no agruparlos por
100000
,10000
y1000
.Por ejemplo, si tiene un archivo llamado
384295.txt
la ruta sería:Si sabes llegarás a unos pocos millones. Usa
0
prefijos para 1,000,000fuente
Para crear un nuevo archivo es necesario escanear el archivo del directorio en busca de suficiente espacio vacío para la nueva entrada del directorio. Si no se encuentra un espacio que sea lo suficientemente grande como para almacenar la nueva entrada del directorio, se colocará al final del archivo del directorio. A medida que aumenta el número de archivos en un directorio, también aumenta el tiempo para escanear el directorio.
Mientras los archivos de directorio permanezcan en la memoria caché del sistema, el rendimiento afectado no será malo, pero si se liberan los datos, leer el archivo de directorio (generalmente muy fragmentado) del disco podría consumir bastante tiempo. Un SSD mejora esto, pero para un directorio con millones de archivos, aún podría haber un impacto notable en el rendimiento.
También es probable que esto requiera tiempo adicional en un directorio con millones de archivos. En un sistema de archivos con entradas de directorio hash (como EXT4), esta diferencia es mínima.
Un árbol de subcarpetas no tiene ninguno de los inconvenientes de rendimiento anteriores. Además, si el sistema de archivos subyacente se cambia para que no tenga nombres de archivo hash, la metodología del árbol seguirá funcionando bien.
fuente
Primero: evite que 'ls' se ordene con 'ls -U', quizás actualice su ~ / bashrc para que tenga 'alias ls = "ls -U"' o similar.
Para su gran conjunto de archivos, puede probar esto así:
crear un conjunto de archivos de prueba
ver si muchos nombres de archivo causan problemas
use el xargs parmeter-batching y el comportamiento zip (predeterminado) de agregar archivos a un zip para evitar problemas.
Esto funcionó bien:
fuente