2011-01-18 7 views
12

Mi servidor utiliza datos de un servicio web interno para construir su respuesta, por solicitud. Estoy usando Apache HttpClient 4.1 para hacer las solicitudes. Cada solicitud inicial dará como resultado aproximadamente 30 solicitudes al servicio web. De estos, 4 - 8 terminarán con enchufes bloqueados en CLOSE_WAIT, que nunca se liberarán. Finalmente, estos sockets atascados exceden mi ulimit y mi proceso se queda sin descriptores de archivo.¿Cómo puedo asegurarme de que mi HttpClient 4.1 no gotea enchufes?

No quiero solo levantar mi ulimit (1024), porque eso enmascara el problema.

La razón por la que me he mudado a HttpClient es que java.net.HttpUrlConnection se comportaba de la misma manera.

He intentado moverme a un SingleClientConnManager por solicitud, y llamar a client.getConnectionManager(). Shutdown() sobre él, pero los sockets todavía terminan bloqueados.

¿Debería tratar de resolver esto para que termine con 0 sockets abiertos mientras no hay solicitudes en ejecución, o debería concentrarme en la persistencia de las solicitudes y la puesta en común?

Para mayor claridad que estoy incluyendo algunos detalles que pueden ser relevantes:

OS: Ubuntu 10.10

JRE: 1.6.0_22

Idioma: Scala 2,8

código

muestra:

val cleaner = Executors.newScheduledThreadPool(1) 
private val client = { 
    val ssl_ctx = SSLContext.getInstance("TLS") 
    val managers = Array[TrustManager](TrustingTrustManager) 
    ssl_ctx.init(null, managers, new java.security.SecureRandom()) 
    val sslSf = new org.apache.http.conn.ssl.SSLSocketFactory(ssl_ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER) 
    val schemeRegistry = new SchemeRegistry() 
    schemeRegistry.register(new Scheme("https", 443, sslSf)) 
    val connection = new ThreadSafeClientConnManager(schemeRegistry) 
    object clean extends Runnable{ 
     override def run = { 
      connection.closeExpiredConnections 
      connection.closeIdleConnections(30, SECONDS) 
     } 
    } 
    cleaner.scheduleAtFixedRate(clean,10,10,SECONDS) 
    val httpClient = new DefaultHttpClient(connection) 
    httpClient.getCredentialsProvider().setCredentials(new AuthScope(AuthScope.ANY), new UsernamePasswordCredentials(username,password)) 
    httpClient 
} 
val get = new HttpGet(uri) 
val entity = client.execute(get).getEntity 
val stream = entity.getContent 
val justForTheExample = IOUtils.toString(stream) 
stream.close() 

Prueba: netstat -a | grep {myInternalWebServiceName} | grep CLOSE_WAIT

(Listas de tomas de corriente para mi proceso que se encuentran en estado CLOSE_WAIT)

Enviar un comentario de discusión:

Este código ahora demuestra el uso correcto.

Respuesta

8

Se necesita desalojar proactivamente las conexiones expiradas/inactivas del grupo de conexiones, ya que en el modelo de E/S de bloqueo las conexiones no pueden reaccionar a los eventos de E/S a menos que se lean/escriban en. Para más detalles ver

http://hc.apache.org/httpcomponents-client-dev/tutorial/html/connmgmt.html#d4e631

+0

Gracias por su respuesta, estoy de acuerdo en que la documentación sugiere que debe ser una medida eficaz. Sin embargo, el número de sockets huérfanos en CLOSE_WAIT sigue creciendo de manera confiable con ese limpiador sin hilos implementado, por lo que no ha sido efectivo. He agregado algunos detalles de implementación a mi pregunta. –

+0

Me retracto. No me había dado cuenta de que en el código de la aplicación real estaba haciendo solicitudes de imágenes suplementarias para realizar la lógica comercial. Seguían usando los métodos WS.url anteriores a la introducción de HttpClient, y dejaban los sockets atrás. –

+0

Enlace roto. (Por favor incluya títulos y descripciones con enlaces.) ¿Tal vez esta es la misma información? http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html – danorton

2

He marcado la respuesta de Oleg como correcto, ya que pone de relieve un importante punto de uso sobre HttpClient la agrupación de conexiones.

Para responder a mi pregunta original específica, sin embargo, que era "¿Debería tratar de resolver para 0 sockets no utilizados o tratar de maximizar la agrupación?"

Ahora que la solución de agrupación está en su lugar y funciona correctamente, el rendimiento de la aplicación se ha incrementado en aproximadamente un 150%. Atribuyo esto a no tener que renegociar SSL y múltiples apretones de manos, sino que reutilizo las conexiones persistentes de acuerdo con HTTP 1.1.

Definitivamente vale la pena trabajar para utilizar la agrupación según lo previsto, en lugar de intentar hackear con la llamada ThreadSafeClientConnManager.shutdown() después de cada solicitud, etcétera.Si, por otro lado, llamaba a hosts arbitrarios y no reutilizaba las rutas de la forma en que lo estoy, podría encontrar fácilmente que es necesario hacer ese tipo de hackers, ya que la JVM podría sorprenderlo con la larga vida útil de los sockets designados de CLOSE_WAIT. no es basura recolectando con mucha frecuencia.

1

Tuve el mismo problema y lo resolví utilizando la sugerencia que se encuentra aquí: here. El autor toca algunos conceptos básicos de TCP:

Cuando una conexión TCP está a punto de cerrarse, su finalización es negociada por ambas partes. Piense en ello como rompiendo un contrato de una manera civilizada. Ambas partes firman el documento y todo está bien. En geek talk, esto se hace a través de los mensajes FIN/ACK. La Parte A envía un mensaje FIN para indicar que quiere cerrar el socket. La Parte B envía un ACK diciendo que recibió el mensaje y está considerando la demanda. La Parte B luego limpia y envía un FIN a la Parte A. La Parte A responde con el ACK y todos se alejan.

El problema viene en cuando B no envía su FIN. A está algo atrapado esperándolo. Tiene inició su secuencia de finalización y está esperando que la otra parte haga lo mismo.

Luego menciones RFC 2616, 14.10 sugerir la creación de una cabecera HTTP para resolver este problema:

postMethod.addHeader("Connection", "close"); 

Honestamente, no sabemos realmente las implicaciones de la creación de esta cabecera. Pero impidió que ocurriera CLOSE_WAIT en mis pruebas unitarias.

Cuestiones relacionadas