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.

Другие вопросы по тегам