【问题标题】:BindException/Too many file open while using HttpClient under loadBindException/在负载下使用 HttpClient 时打开的文件过多
【发布时间】:2010-05-26 15:12:05
【问题描述】:

我有 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。

【问题讨论】:

    标签: java apache-commons-httpclient


    【解决方案1】:

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

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

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

    【讨论】:

    • @Langali:哦,这会教我完整地阅读帖子!要考虑的另一件事是您的操作系统对每个进程打开文件数量的限制是否设置得太低了。当我们发现 Glassfish 几乎所有的分配都用于类加载等时,我们扩展了我们的。这为我们解决了这个问题。
    【解决方案2】:

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

    第二个错误意味着你打开了太多的套接字。在某些系统上,打开文件的限制为 1K。由于挥之不去的套接字和其他打开的文件,您可能刚刚达到了该限制。在 Linux 上,您可以使用

    更改此限制
      ulimit -n 2048
    

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多