Tengo un sitio web que almacenará imágenes de perfil de usuario. Cada imagen se almacena en un directorio (Linux) específico para el usuario. Actualmente tengo una base de clientes de más de 30, lo que significa que tendré más de 30 carpetas. Pero mi actual caja de Linux (ext2 / ext3) no admite la creación de más de 32000 directorios. ¿Cómo paso esto? Incluso los chicos de YouTube tienen el mismo problema, con miniaturas de video. Pero lo resolvieron moviéndose a ReiserFS. ¿No podemos tener una mejor solución?
Actualización: cuando se les preguntó en IRC, la gente preguntaba sobre cómo actualizarlo a ext4, que tiene un límite de 64k y, por supuesto , incluso puede superarlo . O pirateo de kernel para cambiar el límite.
Actualización: ¿Qué hay de dividir la base de usuarios en carpetas en función del rango de ID de usuario? Significa 1-1000 en una carpeta, 1000-2000 en la otra así. Esto parece ser simple. ¿Qué dicen chicos?
Francamente, ¿no hay otra manera?
fuente
Respuestas:
Ese límite es por directorio, no para todo el sistema de archivos, por lo que podría solucionarlo subdividiendo más cosas. Por ejemplo, en lugar de tener todos los subdirectorios de usuario en el mismo directorio, divídalos por los dos primeros caracteres del nombre para que tenga algo como:
Aún mejor sería crear algún tipo de hash de los nombres y usarlo para la división. De esta manera obtendrá una mejor distribución entre los directorios en lugar de, con el ejemplo de letras iniciales, "da" está muy lleno y "zz" está completamente vacío. Por ejemplo, si toma el nombre de CRC o MD5 y usa los primeros 8 bits, obtendrá algo como:
Esto puede extenderse a profundidades adicionales según sea necesario, por ejemplo, si usa el nombre de usuario no un valor hash:
Este método se usa en muchos lugares, como el caché del calamar, para copiar el ejemplo de Ludwig y los cachés locales de los navegadores web.
Una cosa importante a tener en cuenta es que con ext2 / 3 comenzará a tener problemas de rendimiento antes de acercarse al límite de 32,000 de todos modos, ya que los directorios se buscan linealmente. Pasar a otro sistema de archivos (ext4 o reiser, por ejemplo) eliminará esta ineficiencia (reiser busca directorios con un algoritmo dividido en binario para que los directorios largos se manejen de manera mucho más eficiente, ext4 también puede hacerlo), así como el límite fijo por directorio.
fuente
Si está obligado a ext2 / ext3, la única posibilidad que veo es particionar sus datos. Encuentre un criterio que divida sus datos en fragmentos manejables de tamaño similar.
Si solo se trata de las imágenes de perfil que haría:
Por ejemplo, el caché SQUID lo hace de esta manera:
f / 4b / 353ac7303854033
El directorio de nivel superior es el primer dígito hexadecimal, el segundo nivel son los siguientes dos dígitos hexadecimales y el nombre del archivo son los dígitos hexadecimales restantes.
fuente
Tiene una solución mejor: use un sistema de archivos diferente, hay muchos disponibles, muchos de los cuales están optimizados para diferentes tareas. Como señaló, ReiserFS está optimizado para manejar muchos archivos en un directorio.
Vea aquí para una comparación de sistemas de archivos.
Solo alégrate de no estar atascado con NTFS, lo que es realmente abismal para muchos archivos en un directorio. Recomiendo JFS como reemplazo si no te gusta usar el relativamente nuevo (pero aparentemente estable) ext4 FS.
fuente
¿Es pequeña la imagen de perfil? ¿Qué hay de ponerlo en la base de datos con el resto de los datos del perfil? Puede que esta no sea la mejor opción para ti, pero vale la pena considerarla ...
Aquí hay un documento técnico de Microsoft (anterior) sobre el tema: BLOB o no BLOB .
fuente
He pirateado una pequeña galería web, donde terminé con una variación de este problema; "Solo" tenía ~ 30,000 imágenes en el directorio de caché, que resultó ser bastante lento (ext2 usa listas vinculadas para los índices de directorio, según recuerdo).
Terminé haciendo algo en este sentido:
Esto dividirá los datos en 256 directorios, lo que proporciona una búsqueda rápida de directorios para cada uno de los tres niveles.
fuente
No es una respuesta inmediata a su problema, pero hay que tener en cuenta para futuras referencias el proyecto vinculado OpenBSD llamado 'Epitome'
Epitome es un motor que proporciona almacenamiento de instancia única, almacenamiento de contenido direccionable y servicios de deduplicación.
Todos sus datos se almacenan en un almacén de datos como bloques hash, eliminando bloques no únicos para reducir el uso del espacio, y le permite esencialmente olvidarse del mecanismo de almacenamiento, ya que simplemente puede solicitar el contenido del almacén de datos por UUID.
Epitome es actualmente experimental, pero es algo para mirar en el futuro.
fuente
En general, desea evitar tener directorios con una gran cantidad de archivos / directorios. La razón principal es que la expansión de comodines en la línea de comando dará como resultado errores de "Demasiados argumentos" que resultarán en mucho dolor al intentar trabajar con estos directorios.
Busque una solución que haga un árbol más profundo pero más angosto, por ejemplo, creando subcarpetas como otras han descrito.
fuente
Tuvimos un problema similar, la solución, como se mencionó anteriormente, es crear una jerarquía de directorios.
Por supuesto, si tiene una aplicación compleja que se basa en una estructura de directorio plana, probablemente necesitará muchos parches. Por lo tanto, es bueno saber que hay una solución alternativa, use enlaces simbólicos que no tengan el límite de 32k mencionado. Entonces tienes tiempo de sobra para arreglar la aplicación ...
fuente
¿Por qué no utilizar un enfoque de marca de tiempo y luego tener una opción de desbordamiento?
Por ejemplo
Digamos que su marca de tiempo es: 1366587600
Omita los últimos 2 dígitos (o simplemente se vuelve un poco ridículo). Separe el sello en conjuntos de 4 (el recuento de directorios no debe alcanzar más de 9999; si lo desea, puede separarlo de manera diferente).
Esto debería dejarte con algo como esto:
Luego, también verifique la cantidad dentro del directorio antes de cargar, si está recibiendo una gran cantidad de cargas (es decir, 32000 + por 100 segundos), luego itere el directorio por la segunda o una letra, por ejemplo:
o
Luego, registre la marca de tiempo + letra o el código de ruta completo en una base de datos junto con el usuario y debería estar configurado.
sello de ruta: 1366587600 o 13665876a (si usa letras).
Esto termina con una gran cantidad de directorios, pero puede ser realmente útil para manejar revisiones de archivos. Por ejemplo, si un usuario desea usar una nueva imagen de perfil, aún tiene la versión antigua con la marca de tiempo de la anterior en caso de que desee deshacer los cambios (no solo se sobrescribe).
fuente
Sugeriría decidir cuántos subdirectorios máximos desea (o puede) tener en la carpeta principal.
Luego debe convertir su identificación de usuario para que comiencen desde 1.
Entonces puedes hacer:
modulo = currentId % numberOfSubdirectories
modulo
ahora contendrá su número de subdirectorio que nunca será mayor de lonumberOfSubdirectories
que ha elegido.Haz lo que quieras con el módulo, hash, por ejemplo.
También de esta manera los subdirectorios se llenarán linealmente.
fuente