BindException /在加载时使用HttpClient时打开的文件太多

时间:2010-05-26 15:12:06

标签: java apache-commons-httpclient

我有1000个专用的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秒钟或更长时间运行一次,那么一切都运行良好。

我甚至尝试使用shutDown()关闭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的最佳做法是什么?

是的,我还在使用HttpClient3.1。

3 个答案:

答案 0 :(得分:3)

几个月前,这发生在我们身上。首先,仔细检查以确保每次都真正调用releaseConnection()。但即便如此,操作系统实际上并没有立即回收TCP连接。解决方案是使用Apache HTTP Client的MultiThreadedHttpConnectionManager。这会汇集并重用连接。

有关更多性能提示,请参阅http://hc.apache.org/httpclient-3.x/performance.html

更新:哎呀,我没看过下面的代码示例。如果您正在执行releaseConnection()并使用MultiThreadedHttpConnectionManager,请考虑您对每个进程的打开文件的操作系统限制是否设置得足够高。我们也遇到了这个问题,需要稍微扩展一下限制。

答案 1 :(得分:2)

第一次错误没有错。你刚刚耗尽了可用的经验端口。每个TCP连接可以保持TIME_WAIT状态2分钟。你生成2000 /秒。不久之后,套接字找不到任何未使用的本地端口,您将收到该错误。 TIME_WAIT正是为此目的而设计的。没有它,您的系统可能会劫持先前的连接。

第二个错误表示您打开了太多套接字。在某些系统上,打开文件的限制为1K。也许你只是因为延迟套接字和其他打开的文件而达到了这个限制。在Linux上,您可以使用

更改此限制
  ulimit -n 2048

但这受到系统范围最大值的限制。

答案 2 :(得分:0)

以sudo或root编辑/etc/security/limits.conf文件。在“#File of File”上方的文件末尾输入以下值: * soft nofile 65535 * hard nofile 65535 这会将打开的文件数设置为无限制。