2010-10-06 33 views
9

Tenemos un cliente Webstart que se comunica con el servidor mediante el envío de objetos serializados a través de HTTPS usando java.net.HttpsURLConnection.¿Qué podría causar el socket ConnectException: se agotó el tiempo de espera de la conexión?

Todo funciona perfectamente bien en mi máquina local y en servidores de prueba ubicados en nuestra oficina, pero estoy experimentando un problema muy, muy extraño que solo ocurre en nuestros servidores de producción y puesta en escena (y esporádicamente). La principal diferencia que conozco entre esos servidores y los de nuestra oficina es que están ubicados en otra parte y la comunicación entre ellos es considerablemente más lenta, pero también funcionó bien durante mucho tiempo en la producción anterior.

De todos modos, esto es lo que está pasando:

  • El cliente, después de configurar opciones tales como el tiempo de espera y las propiedades tales como Content-Type en el HttpURLConnection leer, llamadas getOutputStream() en él para obtener la corriente a escribir.
  • En este punto, por lo que puedo decir, el cliente se bloquea durante un período de tiempo.
  • El cliente entonces lanza la siguiente excepción:
 
java.net.ConnectException: Connection timed out: connect 
    at java.net.PlainSocketImpl.socketConnect(Native Method) 
    at java.net.PlainSocketImpl.doConnect(Unknown Source) 
    at java.net.PlainSocketImpl.connectToAddress(Unknown Source) 
    at java.net.PlainSocketImpl.connect(Unknown Source) 
    at java.net.SocksSocketImpl.connect(Unknown Source) 
    at java.net.Socket.connect(Unknown Source) 
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.connect(Unknown Source) 
    at com.sun.net.ssl.internal.ssl.BaseSSLSocketImpl.connect(Unknown Source) 
    at sun.net.NetworkClient.doConnect(Unknown Source) 
    at sun.net.www.http.HttpClient.openServer(Unknown Source) 
    at sun.net.www.http.HttpClient.openServer(Unknown Source) 
    at sun.net.www.protocol.https.HttpsClient.(Unknown Source) 
    at sun.net.www.protocol.https.HttpsClient.New(Unknown Source) 
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(Unknown Source) 
    at sun.net.www.protocol.http.HttpURLConnection.plainConnect(Unknown Source) 
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source) 
    at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(Unknown Source) 
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(Unknown Source) 

Tenga en cuenta que esto no es un SocketTimeoutException, que el método connect() en HttpURLConnection dice que lanza si el tiempo de espera expira antes de que se pueda establecer una conexión. Además, cuando esto sucede, yo soy capaz de llamar conn.getResponseCode() y me sale un código de respuesta 200.

  • En el lado del servidor, un EOFException se lanza en el constructor ObjectInputStream 's, que intenta leer el encabezado de serialización pero falla porque el cliente nunca obtiene el OutputStream para escribir.

En caso de que ayuda, aquí están las llamadas que se realizan en el HttpsURLConnection antes de la llamada a getOutputStream() (editado para mostrar solamente se realizan las llamadas en lugar de toda la estructura del código de hacer esto):

HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); 
conn.setUseCaches(false); 
conn.setReadTimeout(30000); 
conn.setRequestProperty("Cookie", cookie); 
conn.setDoOutput(true); 
conn.setRequestProperty("Content-Type", "application/x-java-serialized-object"); 
conn.getOutputStream(); 

La cuestión es que no tengo idea de cómo podría estar ocurriendo algo de esto, especialmente teniendo en cuenta que solo ocasionalmente (no hay un patrón claro de actividad que yo pueda ver) e incluso cuando hay (relativamente) alto latencia entre el cliente y el servidor.

Dado lo que he podido encontrar hasta ahora sobre java.net.ConnectException: Connect timed out, me pregunté si no era un problema de red o firewall en la red en la que se ejecutan nuestros servidores ... pero eso no tiene mucho sentido para dado que la solicitud está llegando claramente al servlet. Además, otras aplicaciones que se ejecutan en la misma red no informaron problemas similares.

¿Alguien tiene alguna idea de la causa de esto, o incluso lo que debo investigar?

+0

de acuerdo con la "evaluación" de http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6319814 java.net.ConnectException puede lanzarse "cualquiera" por un tiempo de espera "o" por cualquier otro motivo de error aleatorio ... si eso ayuda a cualquier – rogerdpack

Respuesta

9

Hemos encontrado estos casos similares a los suyos. Por lo general, a gran carga y no es fácil de reproducir en la prueba. No lo hemos arreglado todavía, pero estos son los pasos que hemos seguido.

Si se trata de un problema de firewall, obtendríamos una conexión rechazada o la excepción SocketTimeout.

1) ¿Puede seguir estas solicitudes en el registro de acceso en el servidor? ¿Muestran un estado HTTP 200 o 404 o algo más? En nuestro caso, los registros del servidor (IIS en este caso) mostraron que el cliente cerró la conexión y no el servidor. Entonces eso fue un misterio.

Actualización: Si el cliente siempre obtiene un 200, entonces el servidor ha enviado realmente volver alguna respuesta pero sospecho que la respuesta de bytes de tamaño (si esto se registra en los registros de acceso) mostrará un valor diferente de la del tamaño de respuesta normal para esa solicitud.

Si muestra el mismo tamaño de la respuesta, entonces usted tiene una condición (no puede ser plausible) que el servidor realidad respondió correctamente pero el cliente no tuvo la respuesta de vuelta porque la conexión termina en algún punto intermedio.

2) Los equipos de administración de red examinaron el tráfico TCP/IP para determinar qué extremo (o enrutador intermedio) está terminando la conversación HTTP/TCP-IP. Y una vez que entendemos cuál es el fin de la conexión, veamos por qué. Alguien con conocimientos suficientes podría ejecutar snoop

3) ¿Hay un número máximo de solicitudes configuradas/restringidas en el servidor? ¿Está estrangulando sus conexiones?

4) ¿Hay balanceadores de carga intermedios en los que se puedan eliminar solicitudes?

Actualización: Una cosa más que queríamos, pero no completamos es crear una ruta estática entre el cliente y el servidor para reducir el número de saltos intermedios y garantizar que no se produzca ninguna conexión relacionada con la red. Ver http://en.wikipedia.org/wiki/Static_routing

5) Otra sugerencia es configurar el ConnectTimeout para ver si funcionan con un valor más alto. Actualización: Es posible que desee probar conn.getErrorStream()

Devuelve el flujo de error si la conexión no pero el servidor envía datos útiles, no obstante. Si la conexión no estaba conectada, o si el servidor no tuvo un error mientras se conecta o si el servidor tuvo un error pero no se envió ningún error, este método devolverá nulo.

6) También podría intentar tomar un conjunto de vuelcos de hilo en el servidor con 5 segundos de diferencia, para ver si algún hilo muestra estas solicitudes entrantes en el servidor.

Actualización: Al día de hoy hemos aprendido a vivir con este problema, porque sumamos la tasa de fracaso para ser 200-300 de 400.000 solicitudes por día, que es 0,00075%

+0

Gracias por tu respuesta. No estoy seguro de los registros de acceso del servidor, pero edité la pregunta para observar que el cliente ve un código de respuesta de 200 después de atrapar la excepción. He experimentado con el valor de tiempo de espera de conexión, pero por lo que pude decir, se lanza 'SocketTimeoutException' cuando se excede eso (en lugar de' ConnectException').No estoy seguro de ninguna de las otras cosas, pero todas parecen valiosas para investigar. – ColinD

+0

@ColinD: ¿Conn.getErrorStream() como en mi actualización muestra algo interesante? – JoseK

+0

No he tenido la oportunidad de probarlo todavía, aunque teniendo en cuenta lo que sucede en el lado del servidor, no estaría escribiendo nada para volver a transmitir al cliente. – ColinD

Cuestiones relacionadas