¿Cuál es el mejor lugar para almacenar imágenes cargadas, una base de datos SQL o un sistema de archivos de disco?

147

Estoy escribiendo una aplicación que permite a los usuarios cargar imágenes en el servidor. Espero alrededor de 20 imágenes por día todas jpeg y probablemente no editado / redimensionado. (Esta es otra pregunta, cómo cambiar el tamaño de las imágenes en el lado del servidor antes de almacenarlas. Quizás alguien pueda soltar un recurso .NET para eso en el comentario más o menos). Ahora me pregunto cuál es el mejor lugar para almacenar imágenes cargadas.

  • Almacene las imágenes como un archivo en el sistema de archivos y cree un registro en una tabla con la ruta exacta a esa imagen.

  • O almacene la imagen en una tabla utilizando un tipo de datos "imagen" o "datos binarios" del servidor de bases de datos.

Veo ventajas y desventajas en ambos. Me gusta a) porque puedo reubicar fácilmente los archivos y solo tengo que cambiar la entrada de la tabla. Por otro lado, no me gusta almacenar datos comerciales en el servidor web y realmente no quiero conectar el servidor web a ninguna otra fuente de datos que contenga datos comerciales (por razones de seguridad) Me gusta b) porque toda la información es en un solo lugar y fácilmente accesible mediante una consulta. Por otro lado, la base de datos se hará muy grande muy pronto. Subcontratar esos datos podría ser más difícil.

Tobias
fuente
2
No lo encontré, ¿dónde?
Tobias

Respuestas:

95

Generalmente almaceno archivos en el sistema de archivos, ya que para eso está allí, aunque hay excepciones. Para los archivos, el sistema de archivos es la solución más flexible y eficiente (generalmente).

Hay algunos problemas con el almacenamiento de archivos en una base de datos (los archivos son generalmente mucho más grandes que la fila promedio), los conjuntos de resultados que contienen muchos archivos grandes consumirán mucha memoria. Además, si usa un motor de almacenamiento que emplea bloqueos de tabla para escrituras (ISAM, por ejemplo), su tabla de archivos puede bloquearse a menudo dependiendo del tamaño / velocidad de los archivos que está almacenando allí.

Con respecto a la seguridad: generalmente almaceno los archivos en un directorio que está fuera de la raíz del documento (no accesible a través de una solicitud http) y los sirvo a través de un script que primero verifica la autorización adecuada.

Eran Galperin
fuente
77
¿Podría explicarme el último párrafo (sobre seguridad) en términos de detalles técnicos o cualquier sugerencia sería muy útil. Gracias.
VishwaKumar
39
(Para todos los googlers) Si tiene la raíz de su sitio configurada en una carpeta "pública" (como en my_website / public / en lugar de solo my_website /), puede almacenar las imágenes en la carpeta my_website / my_images con el resto de tu aplicación Luego, sus etiquetas img harán referencia a "my_website / image.php? Img_id = 55" en lugar de "my_website / avatar.png", y su script image.php, después de verificar sus credenciales y analizar la identificación que le entrega, devolverá el valor real imagen. De esa manera, la imagen solo es visible para el usuario que inició sesión correctamente.
Captain Hypertext
8
Hola capitán, debes convertir eso en una respuesta real para que puedas obtener puntos $$$
Andrew
44
Por favor, añadir unos cuantos más notas en los archivos de seguridad / prevención de la destrucción de su sitio web
Andrew
1
Eso no se escalaría, hay un límite en el número de archivos en la carpeta y si planea dividir sus archivos en varias carpetas, entonces agregaría complejidades para indexar los archivos (para identificar dónde está realmente almacenado el archivo). Además, la búsqueda será muy lenta.
Hardik
43

El único beneficio para la opción B es tener todos los datos en un sistema, ¡pero es un beneficio falso! Puede argumentar que su código también es una forma de datos y, por lo tanto, también puede almacenarse en la base de datos, ¿cómo le gustaría?

A menos que tenga un caso único:

  • La lógica empresarial pertenece al código.
  • Los datos estructurados pertenecen a la base de datos (relacional o no relacional).
  • Los datos a granel pertenecen al almacenamiento (sistema de archivos u otro).

Archivos, Código, Datos

No es necesario utilizar el sistema de archivos para mantener los archivos. En su lugar, puede usar almacenamiento en la nube (como Amazon S3 ) o Infraestructura como servicio además (como Uploadcare ):

https://uploadcare.com/upload-api-cloud-storage-and-cdn/

Pero almacenar archivos en la base de datos es una mala idea.

David Avsajanishvili
fuente
23

Flickr usa el sistema de archivos; discuten las razones aquí

Martin Beckett
fuente
14

Sé que esta es una publicación anterior. Pero muchos visitantes de esta página no obtienen nada relacionado con la pregunta. Especialmente para un novato.

Cómo cargar y almacenar imágenes o archivos en nuestro sitio web:

Para un sitio web estático, puede que no haya ningún problema, ya que el almacenamiento de archivos para algunos alojamientos compartidos sigue siendo adecuado. El problema proviene de un sitio web dinámico cuando se hace más grande. Se puede manejar un tamaño mayor en la base de datos, pero un archivo más grande, como las imágenes, se convierte en un problema. Hay dos tipos de imágenes en un sitio web:

  1. Las imágenes provienen del administrador del blog dinámico. Por lo general, estas imágenes se han optimizado antes de cargarlas.

  2. Las imágenes de los usuarios en caso de usuarios pueden subir imágenes como avatar. O los usuarios pueden crear contenido de blog y poner algunas imágenes del editor de texto. Este tipo de imágenes es difícil de predecir el tamaño. Los usuarios pueden cargar imágenes grandes solo para contenido pequeño cambiando el tamaño del tamaño de la vista pero sin cambiar el tamaño de la imagen.

Al ignorar el artículo no. 1 arriba, solución rápida para el artículo no. 2 puede resolverse temporalmente mediante los siguientes consejos si no tenemos la funcionalidad del optimizador de imagen en nuestro sitio web:

  1. No permita que los usuarios carguen directamente desde el editor de texto redirigiéndolos a la galería de imágenes. En esta página, los usuarios deben cargar el archivo con anticipación antes de poder incrustarlo en el contenido. Este método se llama como administrador de archivos.

  2. Utilice una función de recorte de imagen para que los usuarios carguen imágenes. Esto limitará el tamaño de la imagen, incluso los usuarios cargan archivos muy grandes. La imagen final es el resultado de la imagen recortada. Podemos definir el tamaño en el lado del servidor y aceptar solo, por ejemplo, 500 Kb o menos.

Ahora, eso es solo temporal. Para la solución final, la pregunta se repite:

  • ¿Cómo manejar un gran almacenamiento de imágenes?
  • Cambiar el tamaño o cambiar la extensión.
  • ¿Cómo un sitio web o comercio electrónico grande o mediano maneja el almacenamiento de archivos para sus imágenes?

Qué podemos hacer entonces:

  1. Migre desde el alojamiento compartido VPS. ¿No es suficiente? Luego, más alto al actualizar a Dedicado.

  2. Crea tu propio servidor para el almacenamiento de archivos. Googlear para hacerlo. Esto no es tan difícil como piensas. Algunas personas lo hacen por su sitio web.

  3. La manera fácil es usar el servicio de almacenamiento de archivos CDN.

Bien, 1 y 2 son un poco caros. Pero no 3 creo que es la mejor solución.

Algunos servicios de CDN le permiten almacenar tantos archivos web como desee.

Pregunta, "¿cómo subir archivos a CDN desde nuestro sitio web?"

No se preocupe, una vez que se registre, generalmente gratis, obtendrá orientación sobre cómo cargar archivos y obtener su enlace desde / hacia su sitio web. Obtendrá una API y más. Es fácil.

Algunos proveedores nos brindan un servicio gratuito durante 14 días con almacenamiento y ancho de banda limitados. Pero eso estará bien para el punto de partida. El único problema es porque 'la gente nunca lo intenta'.

Espero que ayude para los novatos.

Sulung Nugroho
fuente
13

Hemos hecho que los clientes insistan en la opción B (almacenamiento de la base de datos) varias veces en algunos backends diferentes, y siempre terminamos volviendo a la opción A (almacenamiento del sistema de archivos) eventualmente.

BLOB grandes como ese simplemente no han sido manejados suficientemente bien incluso por SQL Server 2005, que es el último en el que lo probamos.

Específicamente, vimos hinchazón grave y creo que tal vez problemas de bloqueo.

Otra nota: si está utilizando almacenamiento basado en NTFS (servidor de Windows, etc.), puede considerar encontrar una manera de colocar miles y miles de archivos en un directorio. No estoy seguro de por qué, pero a veces el sistema de archivos no hace frente a esa situación. Si alguien sabe más sobre esto, me encantaría escucharlo.

Pero siempre trato de usar subdirectorios para dividir un poco las cosas. La fecha de creación a menudo funciona bien para esto:

Imágenes / 2008/12/17 / .jpg

... Esto proporciona un nivel de separación decente, y también ayuda un poco durante la depuración. Los clientes Explorer y FTP por igual pueden ahogarse un poco cuando hay directorios realmente enormes.

EDITAR: Solo una nota rápida para 2017, en versiones más recientes de SQL Server, hay nuevas opciones para manejar muchos BLOB que se supone que evitan los inconvenientes que discutí.

EDITAR: Nota rápida para 2020, Blob Storage en AWS / Azure / etc también ha sido una opción durante años. Esto es una gran opción para muchos proyectos basados ​​en la web, ya que es barato y a menudo puede simplificar ciertos problemas relacionados con la implementación, la ampliación a múltiples servidores, la depuración de otros entornos cuando sea necesario, etc.

Brian MacKay
fuente
44
Buena advertencia sobre la cantidad de archivos en el mismo directorio. Puede dar errores demasiado difíciles de encontrar en un entorno de producción.
digao_mb
1
Había golpeado este problema antes. NTFS se comportó de manera impredecible con unos 10,000 archivos en una carpeta.
Faiz
1
No solo NTFS sino también BTRFS, que también tiene problemas para manejar grandes cantidades de imágenes en una carpeta. Es decir, si lo intentaras ls, te llevaría una eternidad (se bloquea). O borrar.
sunapi386
11

Recientemente he creado una aplicación PHP / MySQL que almacena archivos PDF / Word en una tabla MySQL (hasta ahora 40 MB por archivo).

Pros:

  • Los archivos cargados se replican en el servidor de respaldo junto con todo lo demás, no se necesita una estrategia de respaldo separada (tranquilidad).
  • Configurar el servidor web es un poco más simple porque no necesito tener una carga / carpeta y decirle a todas mis aplicaciones dónde está.
  • Puedo usar transacciones para ediciones para mejorar la integridad de los datos: no tengo que preocuparme por los archivos huérfanos y faltantes

Contras:

  • mysqldump ahora lleva mucho tiempo porque hay 500 MB de datos de archivo en una de las tablas.
  • En general, no es muy eficiente en memoria / CPU en comparación con el sistema de archivos

Yo llamaría a mi implementación un éxito, se ocupa de los requisitos de respaldo y simplifica el diseño del proyecto. El rendimiento está bien para las 20-30 personas que usan la aplicación.

demasiado php
fuente
6

Utilizo imágenes cargadas en mi sitio web y definitivamente diría la opción a).

Otra cosa que recomiendo encarecidamente es cambiar inmediatamente el nombre del archivo de lo que el usuario ha llamado la foto, a algo más manejable. Por ejemplo, algo con la fecha y la hora para identificar de forma única cada imagen.

También ayuda a quitar el nombre de archivo del usuario de caracteres extraños para evitar futuras complicaciones.

barfoon
fuente
6

Definitivamente cambie el tamaño de la imagen y compruebe su formato si puede. Ha habido casos de archivos maliciosos que son cargados y servidos por hosts involuntarios, por ejemplo, el GIFAR vulnerabilidad le permitió ocultar un applet java malicioso en un archivo GIF, que luego podría leer las cookies en el contexto actual y enviarlas a otro sitio para un ataque de secuencias de comandos entre sitios. Cambiar el tamaño de las imágenes generalmente evita esto, ya que modifica el código incrustado. Si bien este ataque ha sido reparado por parches JVM, servir ingenuamente archivos binarios sin eliminarlos abre una gran variedad de vulnerabilidades.

Recuerde, la mayoría de los escáneres de virus solo pueden ejecutarse contra el sistema de archivos; si almacena sus archivos binarios en la base de datos, no podrá ejecutar un escáner contra ellos muy fácilmente.

Tim Howland
fuente
4

Esto es básicamente lo que hago.

  1. Almacene una imagen cargada en un directorio temporal o memoria.
  2. Procese esa imagen antes de almacenarla permanentemente. 2.1. Correcciones de color 2.2. Comprimir 2.3. Crear varias copias basadas en las dimensiones de la imagen 2.4. Renombrar con sufijos .xl, .lg, .md, .sm, etc.
  3. Empaquete todos los archivos de imagen procesados ​​(de un solo archivo) dentro de una carpeta con el nombre de la carpeta idque se almacenará en la base de datos para cualquier fila / documento junto con image file name(o puede ser un nombre aleatorio como nombre de imagen).
  4. Cree la carpeta aaaa / mm / d path si no existe. Por ejemplo, 21/08/2016. Recuerde esa ruta y almacene en la base de datos para el mismo documento y fila.
  5. Mueve la idcarpeta de imágenes a la pathcarpeta. (La carpeta de ruta puede ubicarse en la carpeta / var / web-content).
  6. Vaciar el búfer de memoria o eliminar el archivo temporal.

Cuando necesita acceder a cualquier imagen mencionada en un documento, tiene la ruta y la identificación de la carpeta que contiene las imágenes. Por ejemplo/var/web-content/{{path}}/{{id}}/image-file-name.sm.jpg

De esta manera, si tiene que eliminar todos los archivos de imagen procesados, simplemente elimine la carpeta y su contenido será recursivo.

Uday Hiwarale
fuente
3

La mayoría de las implementaciones son la opción A.

Con la opción B, abre una gran lata de whoop4ss cuando reúne esos bits de la base de datos en algo que se puede mostrar en un navegador ... Además, si la base de datos está inactiva, las imágenes no están disponibles.

No creo que el espacio sea un gran problema ... Las unidades de terabyte son un par de cientos de dólares ahora.

Estamos implementando con la opción A porque no tenemos el tiempo o los recursos para hacer la opción B.

mson
fuente
3

Para cambiar el tamaño automáticamente, pruebe imagemagick ... se usa para muchos de los principales sistemas de gestión de contenido / fotos de código abierto ... y creo que hay algunas extensiones .net para ello.

jle
fuente
2

Usamos A. Lo pondría en una unidad compartida (a menos que no planee ejecutar más de un servidor).

Si llega el momento en que esto no escalará para usted, puede investigar los mecanismos de almacenamiento en caché.

csexton
fuente
2

Absolutamente, positivamente la opción A. Otros han mencionado que las bases de datos generalmente no funcionan bien con los BLOB, ya sea que estén diseñados para hacerlo o no. Los sistemas de archivos, por otro lado, viven para estas cosas. Tiene la opción de utilizar el trazado de bandas RAID, distribuir imágenes en varias unidades, incluso distribuirlas en servidores geográficamente dispares.

Otra ventaja es que las copias de seguridad / replicación de su base de datos serían monstruosas.

dj_segfault
fuente
2

Por razones de seguridad, también es una buena práctica evitar los problemas causados ​​por la detección de contenido de IE, que puede permitir a los atacantes cargar JavaScript dentro de archivos de imagen, que podrían ejecutarse en el contexto de su sitio. Por lo tanto, es posible que desee transformar las imágenes (recortarlas o cambiarles el tamaño) de alguna manera antes de almacenarlas para evitar este tipo de ataque. Esta respuesta tiene algunas otras ideas.

Día
fuente
2

Bueno, tengo un proyecto similar donde los usuarios cargan archivos en el servidor. Bajo mi punto de vista, la opción a) es la mejor solución debido a que es más flexible. Lo que debe hacer es almacenar imágenes en una carpeta protegida clasificada por subdirectorios. El administrador debe configurar el directorio principal ya que el contenido no debe ejecutar scripts (muy importante) y (leer, escribir) protegido para que no sea accesible en la solicitud http.

Espero que esto te ayude.

domoindal
fuente
1

Si son archivos pequeños que no necesitarán editarse, entonces la opción B no es una mala opción. Prefiero esto a escribir lógica para almacenar archivos y lidiar con problemas de estructura de directorios locos. Tener muchos archivos en un directorio es malo. emkay?

Si los archivos son grandes o requieren una edición constante, especialmente de programas como Office, entonces la opción A es su mejor opción.

Para la mayoría de los casos, es una cuestión de preferencia, pero si elige la opción A, simplemente asegúrese de que los directorios no contengan demasiados archivos. Si elige la opción B, haga que la tabla con los datos BLOBed esté en su propia base de datos y / o grupo de archivos. Esto ayudará con el mantenimiento, especialmente las copias de seguridad / restauraciones. Sus datos regulares son probablemente bastante pequeños, mientras que los datos de su imagen serán enormes con el tiempo.

Charles Graham
fuente
1

Depende de sus requisitos, especialmente el volumen, los usuarios y la frecuencia de búsqueda. Pero, para una oficina pequeña o mediana, la mejor opción es usar una aplicación como Apple Photos o Adobe Lighroom. Están especializados en almacenar, catalogar, indexar y organizar este tipo de recurso. Pero, para organizaciones grandes, con fuertes requisitos de almacenamiento y gran cantidad de usuarios, se recomienda crear una instancia de una plataforma de gestión de contenido con una gestión de activos digitales, como Nuxeo o Alfresco; ambos ofrecen muy buenos recursos, manejan volúmenes muy grandes de datos con métodos simplificados para recuperarlos. Y, muy importante: hay una opción gratuita (código abierto) para ambas plataformas.

Carlos Camargo
fuente