BindException/Too многие регистрируют открытый при использовании HttpClient при загрузке

У меня есть 1 000 специализированных потоков Java, где каждый поток опрашивает соответствующий URL всех секунду.

public class Poller { 
    public static Node poll(Node node) { 
        GetMethod method =  null; 
        try { 
            HttpClient client = new HttpClient(new SimpleHttpConnectionManager(true)); 
            ......
        } catch (IOException ex) { 
            ex.printStackTrace(); 
        } finally { 
            method.releaseConnection(); 
        } 
    } 
} 

Потоки выполняются всех секунду:

for (int i=0; i <1000; i++) { 
    MyThread thread = threads.get(i) // threads  is a static field 
    if(thread.isAlive()) { 
        // If the previous thread is still running, let it run. 
    } else { 
        thread.start(); 
    } 
}

Проблема состоит в том, если я выполняю задание всех секунду, я получаю случайные исключения как они:

java.net.BindException: Address already in use 
 INFO httpclient.HttpMethodDirector: I/O exception (java.net.BindException) caught when processing request: Address already in use 
 INFO httpclient.HttpMethodDirector: Retrying request 

Но если я выполняю задание каждые 2 секунды или больше, все хорошо работает.

Я даже пытался закрыть экземпляр SimpleHttpConnectionManager () использующий завершение работы () без эффекта.

Если я делаю netstat, я вижу тысячи соединений TCP в состоянии TIME_WAIT, что означает, что они, были закрыты и разрешают.

Таким образом для ограничения никаких из соединений я пытался использовать единственный экземпляр HttpClient, и используйте его как это:

  public class MyHttpClientFactory { 
        private static MyHttpClientFactory instance = new HttpClientFactory(); 
        private MultiThreadedHttpConnectionManager connectionManager; 
        private HttpClient client; 

        private HttpClientFactory() { 
                init(); 
        } 

        public static HttpClientFactory getInstance() { 
                return instance; 
        } 

        public void init() { 
                connectionManager = new MultiThreadedHttpConnectionManager(); 
                HttpConnectionManagerParams managerParams = new HttpConnectionManagerParams(); 
                managerParams.setMaxTotalConnections(1000); 
                connectionManager.setParams(managerParams); 
                client = new HttpClient(connectionManager); 
        } 

        public HttpClient getHttpClient() { 
                if (client != null) { 
                        return client; 
                } else { 
                    init(); 
                    return client; 
                } 
        } 
}

Однако после выполнения в течение точно 2 часов, это начинает бросать 'слишком много открытых файлов' и в конечном счете не может сделать ничего вообще.

ERROR java.net.SocketException: Too many open files
INFO httpclient.HttpMethodDirector: I/O exception (java.net.SocketException) caught when processing request: Too many open files
INFO httpclient.HttpMethodDirector: Retrying request

Я должен смочь не увеличить никакие из позволенных соединений и заставить его работать, но я просто продлил бы зло. Какая-либо идея, что наиболее успешная практика состоит в том, чтобы использовать HttpClient в ситуации как вышеупомянутый?

Btw, я нахожусь все еще на HttpClient3.1.

5
задан skaffman 18 May 2012 в 18:06
поделиться

2 ответа

В первой ошибке нет ничего плохого. Вы только что исчерпали имеющиеся эмпирические порты. Каждое TCP-соединение может оставаться в состоянии TIME_WAIT в течение 2 минут. Вы генерируете 2000 секунд. Рано или поздно сокет не сможет найти неиспользуемый локальный порт, и вы получите эту ошибку. TIME_WAIT предназначен именно для этой цели. Без него ваша система может перехватить предыдущее соединение.

Вторая ошибка означает, что у вас открыто слишком много сокетов. В некоторых системах существует ограничение в 1 КБ открытых файлов. Возможно, вы просто достигли этого предела из-за устаревших сокетов и других открытых файлов. В Linux вы можете изменить это ограничение с помощью

  ulimit -n 2048

, но оно ограничено максимальным общесистемным значением.

2
ответ дан 14 December 2019 в 19:03
поделиться

Это случилось с нами несколько месяцев назад. Во-первых, дважды проверьте, действительно ли вы каждый раз вызываете releaseConnection(). Но даже в этом случае ОС на самом деле не возвращает TCP-соединения все сразу. Решением является использование MultiThreadedHttpConnectionManager HTTP-клиента Apache. Он объединяет и повторно использует соединения.

Дополнительные советы по производительности см. на http://hc.apache.org/httpclient-3.x/performance.html.

Обновление: Упс, я не прочитал нижний пример кода. Если вы выполняете releaseConnection() и используете MultiThreadedHttpConnectionManager, подумайте, достаточно ли высок лимит открытых файлов на процесс в вашей ОС. У нас тоже была такая проблема, и нам пришлось немного расширить лимит.

3
ответ дан 14 December 2019 в 19:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: