La mejor práctica para usar HttpClient en entornos multiproceso

Por un tiempo, he estado usando HttpClient en un entorno multiproceso. Para cada hilo, cuando inicia una conexión, creará una instancia HttpClient completamente nueva.

Recientemente, descubrí que, al usar este enfoque, puede causar que el usuario tenga demasiados puertos abiertos, y la mayoría de las conexiones están en el estado TIME_WAIT.

http://www.opensubscriber.com/message/commons-httpclient-dev@jakarta.apache.org/86045.html

Por lo tanto, en lugar de hacer cada hilo:

HttpClient c = new HttpClient(); try { c.executeMethod(method); } catch(...) { } finally { method.releaseConnection(); } 

Planeamos tener:

[MÉTODO A]

 // global_c is initialized once through // HttpClient global_c = new HttpClient(new MultiThreadedHttpConnectionManager()); try { global_c.executeMethod(method); } catch(...) { } finally { method.releaseConnection(); } 

En una situación normal, se accederá global_c por hilos de 50 ++ de forma concurrente. Me preguntaba, ¿creará esto algún problema de rendimiento? ¿MultiThreadedHttpConnectionManager utiliza un mecanismo sin locking para implementar su política de seguridad de subprocesos?

Si 10 hilos están usando global_c, ¿estarán bloqueados los otros 40 hilos?

¿O sería mejor si, en cada hilo, creo una instancia de un HttpClient, pero lanzo el administrador de conexión explícitamente?

[MÉTODO B]

 MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManager(); HttpClient c = new HttpClient(connman); try { c.executeMethod(method); } catch(...) { } finally { method.releaseConnection(); connman.shutdown(); } 

¿Connman.shutdown () sufrirá problemas de rendimiento?

¿Puedo saber qué método (A o B) es mejor, para la aplicación que usa un hilo 50 ++?

Definitivamente Método A porque está agrupado y es seguro para hilos.

Si está utilizando httpclient 4.x, el administrador de conexión se llama ThreadSafeClientConnManager . Vea este enlace para más detalles (desplácese hacia abajo a “Pooling connection manager”). Por ejemplo:

  HttpParams params = new BasicHttpParams(); SchemeRegistry registry = new SchemeRegistry(); registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); ClientConnectionManager cm = new ThreadSafeClientConnManager(params, registry); HttpClient client = new DefaultHttpClient(cm, params); 

El método A es recomendado por la comunidad de desarrolladores de httpclient.

Consulte http://www.mail-archive.com/httpclient-users@hc.apache.org/msg02455.html para obtener más detalles.

Mi lectura de los documentos es que HttpConnection no se trata como hilo seguro, y por lo tanto MultiThreadedHttpConnectionManager proporciona un grupo reutilizable de HttpConnections, usted tiene un solo MultiThreadedHttpConnectionManager compartido por todos los hilos e inicializado exactamente una vez. Entonces necesitas un par de pequeños refinamientos para la opción A.

 MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManag 

Entonces, cada subproceso debe usar la secuencia para cada solicitud, obtener una conexión de la agrupación y volver a ponerla al finalizar su trabajo, usar un bloque finally puede ser bueno. También debe codificar la posibilidad de que el grupo no tenga conexiones disponibles y procesar la excepción de tiempo de espera.

 HttpConnection connection = null try { connection = connman.getConnectionWithTimeout( HostConfiguration hostConfiguration, long timeout) // work } catch (/*etc*/) {/*etc*/} finally{ if ( connection != null ) connman.releaseConnection(connection); } 

Como está utilizando un conjunto de conexiones, en realidad no estará cerrando las conexiones, por lo que esto no debería afectar al problema TIME_WAIT. Este enfoque supone que cada hilo no se queda en la conexión por mucho tiempo. Tenga en cuenta que el estafador se deja abierto.

Creo que querrá usar ThreadSafeClientConnManager.

Puedes ver cómo funciona aquí: http://foo.jasonhudgins.com/2009/08/http-connection-reuse-in-android.html

O en el AndroidHttpClient que lo usa internamente.

Con HttpClient 4.5 puedes hacer esto:

 CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(new PoolingHttpClientConnectionManager()).build(); 

Tenga en cuenta que este implementa Closeable (para cerrar el administrador de conexión).