¿Cómo puedo asegurarme de que mi HttpClient 4.1 no tenga fugas de sockets?

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 los sockets atascados en CLOSE_WAIT, que nunca se liberarán. Eventualmente, estos conectores atascados exceden mi ulimit y mi proceso se queda sin descriptores de archivos.

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

La razón por la que me mudé a HttpClient es que java.net.HttpUrlConnection se estaba comportando de la misma manera.

He intentado moverme a un SingleClientConnManager por solicitud, y llamar a client.getConnectionManager (). Shutdown () en él, pero los sockets aún se quedan atascados.

¿Debería intentar resolver esto para que termine con 0 sockets abiertos mientras no haya solicitudes en ejecución, o debo concentrarme en la persistencia y agrupación de solicitudes?

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

SO: Ubuntu 10.10

JRE: 1.6.0_22

Idioma: Scala 2.8

Código de 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 sockets para mi proceso que están en estado CLOSE_WAIT)

Publicar comentario discusión:

Este código ahora demuestra el uso correcto.

Es necesario desalojar de forma proactiva las conexiones caducas / inactivas del conjunto de conexiones, ya que en el modelo de locking de E / S las conexiones no pueden reactjsr a los eventos de E / S a menos que se lean o escriban en. Para más detalles ver

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

He marcado la respuesta de oleg como correcta, ya que resalta un punto de uso importante sobre la agrupación de conexiones de HttpClient.

Sin embargo, para responder a mi pregunta original específica, ¿cuál era “debería intentar solucionar 0 sockets no utilizados o tratar de maximizar la agrupación?”

Ahora que la solución de agrupación está en su lugar y funcionando correctamente, el rendimiento de la aplicación ha aumentado en aproximadamente un 150%. Atribuyo esto a no tener que renegociar SSL y varios handshakes, en lugar de reutilizar 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 piratear llamando a ThreadSafeClientConnManager.shutdown () después de cada solicitud, etc. Si, por otro lado, llamaba a hosts arbitrarios y no reutilizaba las rutas de la forma en que estoy, podría encontrar fácilmente que es necesario hacer ese tipo de piratería, ya que la JVM podría sorprenderlo con la larga vida de sockets designados CLOSE_WAIT si No recoges basura muy a menudo.

Tuve el mismo problema y lo resolví utilizando las sugerencias que se encuentran aquí: aquí . 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 romper un contrato de una manera civilizada. Ambas partes firman el papel 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 zócalo. 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 van.

El problema viene cuando B no envía su FIN. A está un poco atascado esperándolo. Ha iniciado su secuencia de finalización y está esperando que la otra parte haga lo mismo.

Luego menciona RFC 2616, 14.10 para sugerir la configuración de un encabezado http para resolver este problema:

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

Honestamente, no sé realmente las implicaciones de establecer este encabezado. Pero no impidió que CLOSE_WAIT pasara en mis pruebas de unidad.