Apache HttpClient - нужно использовать MultiThreadedHttpConnectionManager?
У меня есть сервер, который получает запросы от клиентов и на основе запросов подключается к некоторому внешнему веб-сайту и выполняет некоторые операции.
Я использую Apache Commons HttpClient
(v 2.0.2), чтобы сделать эти соединения (я знаю, что он старый, но я должен использовать его из-за других ограничений).
Мой сервер не будет получать частые запросы. Я думаю, что это может быть много запросов при первом развертывании. Тогда будет только несколько запросов в день. Могут быть случайные всплески, когда снова появляется много запросов.
Все соединения будут одним из 3-х URL-адресов - это могут быть http или https
Я думал об использовании отдельных случаев HttpClient
за каждый запрос
Есть ли необходимость для меня использовать общий HttpClient
возражать и использовать его с MultiThreadedHttpConnectionManager
для разных соединений. Как именно MultiThreadedHttpConnectionManager помогает - поддерживает ли оно соединение открытым даже после вызова releaseConnection? Как долго это будет держать это открытым?
Все мои соединения будут ПОЛУЧЕНЫ, и они будут возвращать не более 10-20 байт. Я ничего не скачиваю. Причина я использую HttpClient
а не основные библиотеки Java, потому что иногда я могу использовать HTTP 1.0 (я не думаю, что классы Java поддерживают это), и я также могу хотеть делать перенаправления Http автоматически.
2 ответа
Я использую PoolingHttpClientConnectionManager
в значительно многопоточной среде, и это работает очень хорошо.
Вот реализация клиентского пула:
public class HttpClientPool {
// Single-element enum to implement Singleton.
private static enum Singleton {
// Just one of me so constructor will be called once.
Client;
// The thread-safe client.
private final CloseableHttpClient threadSafeClient;
// The pool monitor.
private final IdleConnectionMonitor monitor;
// The constructor creates it - thus late
private Singleton() {
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
// Increase max total connection to 200
cm.setMaxTotal(200);
// Increase default max connection per route to 200
cm.setDefaultMaxPerRoute(200);
// Make my builder.
HttpClientBuilder builder = HttpClients.custom()
.setRedirectStrategy(new LaxRedirectStrategy())
.setConnectionManager(cm);
// Build the client.
threadSafeClient = builder.build();
// Start up an eviction thread.
monitor = new IdleConnectionMonitor(cm);
// Start up the monitor.
Thread monitorThread = new Thread(monitor);
monitorThread.setDaemon(true);
monitorThread.start();
}
public CloseableHttpClient get() {
return threadSafeClient;
}
}
public static CloseableHttpClient getClient() {
// The thread safe client is held by the singleton.
return Singleton.Client.get();
}
public static void shutdown() throws InterruptedException, IOException {
// Shutdown the monitor.
Singleton.Client.monitor.shutdown();
}
// Watches for stale connections and evicts them.
private static class IdleConnectionMonitor implements Runnable {
// The manager to watch.
private final PoolingHttpClientConnectionManager cm;
// Use a BlockingQueue to stop everything.
private final BlockingQueue<Stop> stopSignal = new ArrayBlockingQueue<Stop>(1);
IdleConnectionMonitor(PoolingHttpClientConnectionManager cm) {
this.cm = cm;
}
public void run() {
try {
// Holds the stop request that stopped the process.
Stop stopRequest;
// Every 5 seconds.
while ((stopRequest = stopSignal.poll(5, TimeUnit.SECONDS)) == null) {
// Close expired connections
cm.closeExpiredConnections();
// Optionally, close connections that have been idle too long.
cm.closeIdleConnections(60, TimeUnit.SECONDS);
}
// Acknowledge the stop request.
stopRequest.stopped();
} catch (InterruptedException ex) {
// terminate
}
}
// Pushed up the queue.
private static class Stop {
// The return queue.
private final BlockingQueue<Stop> stop = new ArrayBlockingQueue<Stop>(1);
// Called by the process that is being told to stop.
public void stopped() {
// Push me back up the queue to indicate we are now stopped.
stop.add(this);
}
// Called by the process requesting the stop.
public void waitForStopped() throws InterruptedException {
// Wait until the callee acknowledges that it has stopped.
stop.take();
}
}
public void shutdown() throws InterruptedException, IOException {
// Signal the stop to the thread.
Stop stop = new Stop();
stopSignal.add(stop);
// Wait for the stop to complete.
stop.waitForStopped();
// Close the pool.
HttpClientPool.getClient().close();
// Close the connection manager.
cm.close();
}
}
}
Все, что вам нужно сделать, это CloseableHttpResponse conversation = HttpClientPool.getClient().execute(request);
и когда вы закончили с этим, просто close
он и будет возвращен в бассейн.
Я думаю, что все зависит от того, каковы ваши SLA и если производительность находится в пределах приемлемого / ожидаемого времени отклика. Ваше решение будет работать без каких-либо проблем, но оно не масштабируется, если требования вашего приложения со временем растут.
С помощью MultiThreadedHttpConnectionManager
это гораздо более элегантное / масштабируемое решение, чем управление 3 независимыми объектами HttpClient.