es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

AWS S3 (con SDK 2.x) – ¿Están disponibles las opciones de carga de archivos a S3 (con menor consumo de memoria y sin archivo temporal)?

Recientemente hemos decidido migrar los casos de uso de carga/descarga de archivos Java para que sean atendidos a través de AWS S3 en lugar de nuestro antiguo SFTP VM. Mis tamaños de archivo suelen estar entre 0 y 10 MB y puede haber varios usuarios concurrentes (API de Java) que carguen los archivos.

Mientras hacía eso, me encontré con 4 opciones principales para cargar el archivo en el bucket de S3.

  • OPCIÓN_1: InputStream a byteArray
RequestBody.fromBytes(IoUtils.toByteArray(s3FileObject.getInputStream()));

/// Esto consume mucha memoria ya que lee todo el flujo en un byteArray y luego lo escribe en S3 a través de putObject.

  • OPCIÓN_2: Como InputStream
RequestBody.fromInputStream(s3FileObject.getInputStream(), s3FileObject.getInputStream().available());

/// Aquí realmente no tengo el tamaño del InputStream (ya que s3FileObject.getInputStream().available() no siempre es correcto para obtener la longitud del InputStream).

  • OPCIÓN_3: InputStream a archivo
RequestBody.fromFile(file);

/// Realmente no quiero crear el archivo temporal en mi servidor Java o en la carpeta temporal ya que es una carga adicional en comparación con nuestro enfoque inicial de carga en VM a través de SFTP.

  • OPCIÓN_4: Subida multipartita
s3.uploadPart(part, RequestBody.fromBytes(bytes)).eTag();

// El tamaño mínimo de la parte es de 5 MB, por lo que varios usuarios, digamos 100, cargando esos archivos pueden consumir mucha memoria.

Cómo lo estaba implementando anteriormente
Teníamos Apache VFS que solía abrir el OutputStream al archivo SFTP, y solíamos leer pequeños fragmentos del InputStream y escribir en el OutputStream (que es el archivo en SFTP).

Código de muestra

public long transferStream(InputStream inputStream, OutputStream outputStream) throws IOException
{
    int bytesRead = 0;
    long streamSize = 0;
    byte[] buf = new byte[4 * 1024];
    while ((bytesRead = inputStream.read(buf)) != -1)
    {
        streamSize += bytesRead;
        outputStream.write(buf, 0, bytesRead);
        outputStream.flush();
    }
    outputStream.flush();
    return streamSize;
}
  • Tengo 2 preguntas aquí
    1) ¿Hay alguna manera de obtener el OutputStream del archivo de S3 y escribir con pequeños fragmentos como en el método anterior?
    2) Para la aplicación con una máquina de 4 GB y 2 GB de XMX, ¿cómo funcionará la opción del archivo temporal (OPCIÓN_3 arriba) incluso después de eliminar los archivos después de la carga?

¿Existe alguna mejor manera de manejar la carga de S3 sin demasiada sobrecarga de memoria y archivos temporales?

Gracias

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    1) Sí, puedes obtener el flujo de salida de un archivo S3 usando el método AmazonS3Client.putObject(String bucketName, String key, InputStream input, ObjectMetadata metadata), el cual retorna un OutputStream. Luego, puedes escribir en este OutputStream en pequeños fragmentos como lo estabas haciendo con el flujo de salida de SFTP. De esta forma puedes evitar consumir mucha memoria al no tener que leer todo el InputStream en un arreglo de bytes.

    2) Si eliges la opción de crear un archivo temporal, funcionará bien siempre y cuando tengas suficiente espacio en disco en tu servidor. Una vez que la carga esté completa, puedes eliminar el archivo temporal. Sin embargo, si tienes un espacio en disco limitado, la creación de archivos temporales grandes podría causar que la aplicación falle debido a la falta de espacio en disco. En ese caso, se recomienda usar una de las otras opciones mencionadas anteriormente.

    No existe una solución única para manejar las cargas en S3 sin un exceso de memoria y archivos temporales. El enfoque óptimo depende de tus casos de uso y restricciones específicas. Sin embargo, usar una combinación de las opciones disponibles puede ayudar a mitigar las desventajas de cada opción individual. Por ejemplo, puedes usar la opción de carga multipartes para archivos grandes y la opción de flujo de entrada para archivos más pequeños.

Comments are closed.