2012-03-31 14 views
10

Tengo una aplicación que funciona mucho en S3, principalmente descargando archivos desde él. Estoy viendo muchos de estos tipos de errores y me gustaría saber si esto es algo en mi código o si el servicio no es confiable como este.El cliente S3 Java falla mucho con el "cuerpo del mensaje delimitado por el final prematuro del contenido" o "el socket cerrado por java.net.SocketException"

El código que estoy usando para leer de la corriente objeto S3 es el siguiente:

public static final void write(InputStream stream, OutputStream output) { 

    byte[] buffer = new byte[1024]; 

    int read = -1; 

    try { 

    while ((read = stream.read(buffer)) != -1) { 
     output.write(buffer, 0, read); 
    } 

    stream.close(); 
    output.flush(); 
    output.close(); 
    } catch (IOException e) { 
    throw new RuntimeException(e); 
    } 

} 

Este OutputStream es una nueva BufferedOutputStream (nueva FileOutputStream (archivo)). Estoy utilizando la última versión del cliente Amazon S3 Java y esta llamada se reintenta cuatro veces antes de darse por vencido. Entonces, después de probar esto por 4 veces, aún falla.

Se agradecen todos los consejos sobre cómo podría mejorar esto.

+0

qué sucede con todos (o la mayoría) de los archivos, con los archivos al azar, o con un conjunto limitado y reproducible? ¿Está configurando Metadatos antes de la primera carga? He visto casos en los que los metadatos (o la falta de) en algunos archivos pueden causar algunos problemas extraños. Si aún no lo has probado, puede valer la pena intentarlo. –

+0

archivos en su mayoría aleatorios y no utilizamos ningún metadato :( –

+0

Solo una aproximación. ¿Se ha asegurado de que esos archivos aleatorios se carguen correctamente en s3? Intente descargar esos archivos mediante la solicitud GET o alguna otra herramienta. – shashankaholic

Respuesta

12

Acabo de superar un problema muy similar. En mi caso, la excepción que recibía era idéntica; sucedió con archivos más grandes pero no con archivos pequeños, y nunca sucedió en absoluto al pasar por el depurador.

La causa principal del problema era que el objeto AmazonS3Client estaba recibiendo basura recolectada en el medio de la descarga, lo que provocó que se rompiese la conexión de red. Esto sucedió porque estaba construyendo un nuevo objeto AmazonS3Client con cada llamada para cargar un archivo, mientras que el caso de uso preferido es crear un objeto cliente duradero que sobreviva en llamadas, o al menos se garantice que esté disponible durante la totalidad del proceso. descargar. Entonces, el remedio simple es asegurarse de que se mantenga una referencia a AmazonS3Client para que no se obtenga GC'd.

Un enlace en los foros de AWS que me ayudaron está aquí: https://forums.aws.amazon.com/thread.jspa?threadID=83326

+0

Mantener el objeto del cliente dentro del método hizo el truco, ouch. Gracias Steve! –

0
  1. Trate de usar wireshark para ver lo que está sucediendo en el cable cuando esto sucede.

  2. Pruebe reemplazar temporalmente S3 con su propio servidor web y verifique si el problema persiste. Si lo hace, es tu código y no S3.

El hecho de que sea aleatorio sugiere problemas de red entre su host y algunos de los hosts S3.

1

En primer lugar, su código está funcionando completamente normalmente si (y solo si) sufre problemas de conectividad entre usted y Amazon S3. Como Michael Slade points out, se aplica una advertencia de depuración de nivel de conexión estándar.

En cuanto a su código fuente real, observo algunos olores de código que debe tener en cuenta. La anotación de ellos directamente en la fuente:

public static final void write(InputStream stream, OutputStream output) { 

    byte[] buffer = new byte[1024]; // !! Abstract 1024 into a constant to make 
            // this easier to configure and understand. 

    int read = -1; 

    try { 

    while ((read = stream.read(buffer)) != -1) { 
     output.write(buffer, 0, read); 
    } 

    stream.close(); // !! Unexpected side effects: closing of your passed in 
        // InputStream. This may have unexpected results if your 
        // stream type supports reset, and currently carries no 
        // visible documentation. 

    output.flush(); // !! Violation of RAII. Refactor this into a finally block, 
    output.close(); // a la Reference 1 (below). 

    } catch (IOException e) { 
    throw new RuntimeException(e); // !! Possibly indicative of an outer 
            // try-catch block for RuntimeException. 
            // Consider keeping this as IOException. 
    } 
} 

(Reference 1)

De lo contrario, el propio código parece estar bien. Las excepciones IO deben ser situaciones esperadas en situaciones en las que se conecta a un host remoto voluble, y lo mejor que puede hacer es redactar una política sensata para almacenar en caché y volver a conectar en estos escenarios.

0

También S3 podría cerrar conexiones lentas según mi experiencia.

+0

Si es posible, intente almacenar su flujo de entrada en un archivo y cárguelo en S3 a través del navegador usando POST (reemplace su código de servidor Java en el navegador en el misma máquina para averiguar si el problema está en su código) –

0

Me gustaría echar un vistazo muy de cerca al equipo de red más cercano a la aplicación de su cliente. Este problema huele a que algunos dispositivos de red eliminan paquetes entre usted y el servicio. Mire para ver si hubo un punto de partida cuando ocurrió el problema por primera vez. ¿Hubo algún cambio, como una actualización de firmware en un enrutador o el reemplazo de un conmutador en ese momento?

Verifique el uso del ancho de banda en comparación con la cantidad comprada a su ISP. ¿Hay momentos del día en los que te estás acercando a ese límite? ¿Puedes obtener gráficos de tu uso de ancho de banda? Vea si las terminaciones prematuras pueden correlacionarse con el uso de gran ancho de banda, particularmente si se acerca a algún límite conocido. ¿El problema parece abarcar archivos más pequeños y archivos grandes solo cuando están casi terminados de descargarse? Comprar más ancho de banda de su ISP puede solucionar el problema.

+0

Estas son máquinas EC2 que se conectan a máquinas S3, no hay ningún tipo de límite. Pero gracias de todos modos :) –

3

La red está cerrando la conexión, antes de que el cliente obtenga todos los datos, por una razón u otra, eso es lo que está sucediendo.

Parte de cualquier solicitud de HTTP es la longitud del contenido, su código está recibiendo el encabezado, diciendo hola amigo, aquí hay datos, y esto es gran parte ... y luego la conexión está cayendo antes de que el cliente haya leído todos los datos ... por lo que su bombardeo a cabo con la excepción.

Me gustaría ver la configuración de tiempo de espera de la conexión OS/NETWORK/JVM (aunque JVM generalmente hereda del sistema operativo en esta situación). La clave es descubrir qué parte de la red está causando el problema. ¿Es su configuración de nivel de equipo que dice, no, que no va a esperar más para los paquetes ... es que está utilizando una lectura no bloqueante, que tiene una configuración de tiempo de espera en su código, donde está diciendo, hey, no ha llegado cualquier dato del servidor desde más tiempo de lo que se supone que debo esperar, así que voy a desconectar la conexión y la excepción. etc.etc etc.

La mejor apuesta es a nivel bajo husmear el tráfico de paquetes y rastrear hacia atrás, para ver dónde se produce la caída de la conexión, o ver si puede tiempo de espera en cosas que puede controlar, como su software y sistema operativo/JVM.

+0

Eso es genial, nos encontramos con este problema por un tiempo ahora y también tiene problemas de tiempo de espera con nuestro Load Balancer. Por alguna razón, no me di cuenta de que los dos podrían ser lo mismo. –

Cuestiones relacionadas