Almacene eficientemente cientos de millones de archivos pequeños. Solución autohospedada

Almacene eficientemente cientos de millones de archivos pequeños. Solución autohospedada

Estimada comunidad: Este artículo se centrará en almacenar y recuperar de manera eficiente cientos de millones de archivos pequeños. En esta etapa, se propone la solución final para sistemas de archivos compatibles con POSIX con soporte completo para bloqueos, incluidos bloqueos de clúster, y aparentemente incluso sin muletas.

Entonces escribí mi propio servidor personalizado para este propósito.
Durante la implementación de esta tarea, logramos resolver el problema principal y al mismo tiempo ahorrar espacio en disco y RAM, que nuestro sistema de archivos de clúster consumía sin piedad. En realidad, tal cantidad de archivos es perjudicial para cualquier sistema de archivos agrupado.

La idea es esta:

En palabras simples, los archivos pequeños se cargan a través del servidor, se guardan directamente en el archivo y también se leen, y los archivos grandes se colocan uno al lado del otro. Esquema: 1 carpeta = 1 archivo, en total tenemos varios millones de archivos con archivos pequeños, y no varios cientos de millones de archivos. Y todo esto se implementa completamente, sin scripts ni guardar archivos en archivos tar/zip.

Intentaré ser breve, pido disculpas de antemano si la publicación es larga.

Todo comenzó con el hecho de que no podía encontrar un servidor adecuado en el mundo que pudiera guardar los datos recibidos a través del protocolo HTTP directamente en archivos, sin las desventajas inherentes a los archivos y almacenamiento de objetos convencionales. Y el motivo de la búsqueda fue el clúster Origin de 10 servidores que había crecido a gran escala, en el que ya se habían acumulado 250,000,000 de archivos pequeños, y la tendencia de crecimiento no iba a detenerse.

Para aquellos a quienes no les gusta leer artículos, un poco de documentación es más fácil:

aquí и aquí.

Y Docker al mismo tiempo, ahora hay una opción solo con nginx dentro por si acaso:

docker run -d --restart=always -e host=localhost -e root=/var/storage 
-v /var/storage:/var/storage --name wzd -p 80:80 eltaline/wzd

Siguiente:

Si hay muchos archivos, se necesitan importantes recursos y lo peor es que algunos de ellos se desperdician. Por ejemplo, cuando se utiliza un sistema de archivos en clúster (en este caso, MooseFS), el archivo, independientemente de su tamaño real, siempre ocupa al menos 64 KB. Es decir, para archivos de 3, 10 o 30 KB de tamaño, se requieren 64 KB en disco. Si hay 2 millones de archivos, perdemos de 10 a 1 terabytes. No será posible crear nuevos archivos de forma indefinida, ya que MooseFS tiene una limitación: no más de mil millones con una réplica de cada archivo.

A medida que aumenta la cantidad de archivos, se necesita mucha RAM para los metadatos. Los frecuentes volcados de metadatos de gran tamaño también contribuyen al desgaste de las unidades SSD.

Servidor wZD. Ponemos las cosas en orden en los discos.

El servidor está escrito en Go. En primer lugar, necesitaba reducir la cantidad de archivos. ¿Cómo hacerlo? Debido al archivado, pero en este caso sin compresión, ya que mis archivos son sólo imágenes comprimidas. BoltDB acudió al rescate, que aún tenía que corregir sus deficiencias, como se refleja en la documentación.

En total, en lugar de 10 millones de archivos, en mi caso sólo quedaban 1 millones de archivos de Bolt. Si tuviera la oportunidad de cambiar la estructura de archivos del directorio actual, sería posible reducirla a aproximadamente XNUMX millón de archivos.

Todos los archivos pequeños se empaquetan en archivos Bolt, que reciben automáticamente los nombres de los directorios en los que se encuentran, y todos los archivos grandes permanecen junto a los archivos; no tiene sentido empaquetarlos, esto es personalizable. Los pequeños se archivan, los grandes se dejan sin cambios. El servidor funciona de forma transparente con ambos.

Arquitectura y características del servidor wZD.

Almacene eficientemente cientos de millones de archivos pequeños. Solución autohospedada

El servidor opera bajo los sistemas operativos Linux, BSD, Solaris y OSX. Solo probé la arquitectura AMD64 en Linux, pero debería funcionar para ARM64, PPC64, MIPS64.

Principales características:

  • subprocesos múltiples;
  • Multiservidor, que proporciona tolerancia a fallos y equilibrio de carga;
  • Máxima transparencia para el usuario o desarrollador;
  • Métodos HTTP soportados: GET, HEAD, PUT y DELETE;
  • Control del comportamiento de lectura y escritura a través de encabezados de cliente;
  • Soporte para hosts virtuales flexibles;
  • Admite la integridad de los datos CRC al escribir/leer;
  • Búfers semidinámicos para un consumo mínimo de memoria y un ajuste óptimo del rendimiento de la red;
  • Compactación de datos diferida;
  • Además, se ofrece un archivador multiproceso wZA para migrar archivos sin detener el servicio.

Experiencia real:

He estado desarrollando y probando el servidor y el archivador con datos en vivo durante bastante tiempo, ahora está funcionando con éxito en un clúster que incluye 250,000,000 de archivos pequeños (imágenes) ubicados en 15,000,000 directorios en unidades SATA separadas. Un grupo de 10 servidores es un servidor Origin instalado detrás de una red CDN. Para darle servicio se utilizan 2 servidores Nginx + 2 servidores wZD.

Para aquellos que decidan utilizar este servidor, sería aconsejable planificar la estructura del directorio, si corresponde, antes de usarlo. Permítanme hacer una reserva de inmediato: el servidor no está destinado a meter todo en un archivo de 1 Bolt.

Pruebas de rendimiento:

Cuanto menor sea el tamaño del archivo comprimido, más rápidas se realizarán las operaciones GET y PUT en él. Comparemos el tiempo total de escritura del cliente HTTP con archivos normales y archivos Bolt, así como de lectura. Se compara el trabajo con archivos de tamaños 32 KB, 256 KB, 1024 KB, 4096 KB y 32768 KB.

Cuando se trabaja con archivos Bolt, se verifica la integridad de los datos de cada archivo (se usa CRC), antes y después de grabar, se realiza la lectura y el recálculo sobre la marcha, esto naturalmente introduce retrasos, pero lo principal es la seguridad de los datos.

Realicé pruebas de rendimiento en unidades SSD, ya que las pruebas en unidades SATA no muestran una diferencia clara.

Gráficos basados ​​en los resultados de las pruebas:

Almacene eficientemente cientos de millones de archivos pequeños. Solución autohospedada
Almacene eficientemente cientos de millones de archivos pequeños. Solución autohospedada

Como puede ver, para archivos pequeños la diferencia en los tiempos de lectura y escritura entre archivos archivados y no archivados es pequeña.

Obtenemos una imagen completamente diferente cuando probamos la lectura y escritura de archivos de 32 MB de tamaño:

Almacene eficientemente cientos de millones de archivos pequeños. Solución autohospedada

La diferencia de tiempo entre la lectura de archivos es de 5 a 25 ms. Con la grabación la cosa va peor, la diferencia es de unos 150 ms. Pero en este caso no es necesario cargar archivos grandes, simplemente no tiene sentido hacerlo, pueden vivir separados de los archivos.

*Técnicamente, puedes utilizar este servidor para tareas que requieran NoSQL.

Métodos básicos para trabajar con el servidor wZD:

Cargando un archivo normal:

curl -X PUT --data-binary @test.jpg http://localhost/test/test.jpg

Cargar un archivo al archivo Bolt (si no se excede el parámetro del servidor fmaxsize, que determina el tamaño máximo de archivo que se puede incluir en el archivo; si se excede, el archivo se cargará como de costumbre junto al archivo):

curl -X PUT -H "Archive: 1" --data-binary @test.jpg http://localhost/test/test.jpg

Descargar un archivo (si hay archivos con los mismos nombres en el disco y en el archivo, al descargar, se le da prioridad de forma predeterminada al archivo no archivado):

curl -o test.jpg http://localhost/test/test.jpg

Descarga de un archivo del archivo Bolt (forzado):

curl -o test.jpg -H "FromArchive: 1" http://localhost/test/test.jpg

Las descripciones de otros métodos se encuentran en la documentación.

Documentación WZD
Documentación de la WZA

Actualmente, el servidor solo admite el protocolo HTTP; todavía no funciona con HTTPS. El método POST tampoco es compatible (aún no se ha decidido si es necesario o no).

Quien profundice en el código fuente encontrará caramelo allí, no a todos les gusta, pero no vinculé el código principal a las funciones del marco web, excepto el controlador de interrupciones, por lo que en el futuro puedo reescribirlo rápidamente para casi cualquier motor.

Tareas:

  • Desarrollo de replicador y distribuidor propio + geo para posibilidad de uso en sistemas grandes sin sistemas de archivos cluster (Todo para adultos)
  • Posibilidad de recuperación inversa completa de los metadatos si se pierden por completo (si se utiliza un distribuidor)
  • Protocolo nativo para la capacidad de utilizar conexiones de red persistentes y controladores para diferentes lenguajes de programación.
  • Posibilidades avanzadas de utilizar el componente NoSQL.
  • Compresiones de diferentes tipos (gzip, zstd, snappy) para archivos o valores dentro de archivos Bolt y para archivos normales
  • Cifrado de diferentes tipos para archivos o valores dentro de archivos Bolt y para archivos normales
  • Conversión de video retrasada del lado del servidor, incluso en GPU

Lo tengo todo, espero que a alguien le sirva este servidor, licencia BSD-3, doble copyright, ya que si no hubiera empresa donde trabajo el servidor no se hubiera escrito. Soy el único desarrollador. Estaría agradecido por cualquier error y solicitud de funciones que encuentre.

Fuente: habr.com

Añadir un comentario