java 如何确保我的 HttpClient 4.1 不会泄漏套接字?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4724193/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I ensure that my HttpClient 4.1 does not leak sockets?
提问by Chris Hagan
My server uses data from an internal web service to construct its response, on a per request basis. I'm using Apache HttpClient 4.1 to make the requests. Each initial request will result in about 30 requests to the web service. Of these, 4 - 8 will end up with sockets stuck in CLOSE_WAIT, which never get released. Eventually these stuck sockets exceed my ulimit and my process runs out of file descriptors.
我的服务器基于每个请求使用来自内部 Web 服务的数据来构建其响应。我正在使用 Apache HttpClient 4.1 发出请求。每个初始请求将导致对 Web 服务的大约 30 个请求。其中,4 - 8 个套接字最终会卡在 CLOSE_WAIT 中,永远不会被释放。最终,这些卡住的套接字超过了我的 ulimit,我的进程用完了文件描述符。
I don't want to just raise my ulimit (1024), because that will just mask the problem.
我不想只是提高我的 ulimit (1024),因为那只会掩盖问题。
The reason I've moved to HttpClient is that java.net.HttpUrlConnection was behaving the same way.
我转移到 HttpClient 的原因是 java.net.HttpUrlConnection 的行为方式相同。
I have tried moving to a SingleClientConnManager per request, and calling client.getConnectionManager().shutdown() on it, but sockets still end up stuck.
我曾尝试根据请求移动到 SingleClientConnManager,并在其上调用 client.getConnectionManager().shutdown(),但套接字最终仍然卡住。
Should I be trying to solve this so that I end up with 0 open sockets while there are no running requests, or should I be concentrating on request persistence and pooling?
我应该尝试解决这个问题,以便在没有运行请求的情况下最终获得 0 个打开的套接字,还是应该专注于请求持久性和池化?
For clarity I'm including some details which may be relevant:
为清楚起见,我包含了一些可能相关的细节:
OS: Ubuntu 10.10
操作系统: Ubuntu 10.10
JRE: 1.6.0_22
JRE:1.6.0_22
Language: Scala 2.8
语言:Scala 2.8
Sample code:
示例代码:
val cleaner = Executors.newScheduledThreadPool(1)
private val client = {
val ssl_ctx = SSLContext.getInstance("TLS")
val managers = Array[TrustManager](TrustingTrustManager)
ssl_ctx.init(null, managers, new java.security.SecureRandom())
val sslSf = new org.apache.http.conn.ssl.SSLSocketFactory(ssl_ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
val schemeRegistry = new SchemeRegistry()
schemeRegistry.register(new Scheme("https", 443, sslSf))
val connection = new ThreadSafeClientConnManager(schemeRegistry)
object clean extends Runnable{
override def run = {
connection.closeExpiredConnections
connection.closeIdleConnections(30, SECONDS)
}
}
cleaner.scheduleAtFixedRate(clean,10,10,SECONDS)
val httpClient = new DefaultHttpClient(connection)
httpClient.getCredentialsProvider().setCredentials(new AuthScope(AuthScope.ANY), new UsernamePasswordCredentials(username,password))
httpClient
}
val get = new HttpGet(uri)
val entity = client.execute(get).getEntity
val stream = entity.getContent
val justForTheExample = IOUtils.toString(stream)
stream.close()
Test: netstat -a | grep {myInternalWebServiceName} | grep CLOSE_WAIT
测试:netstat -a | grep {myInternalWebServiceName} | grep CLOSE_WAIT
(Lists sockets for my process that are in CLOSE_WAIT state)
(列出我的进程处于 CLOSE_WAIT 状态的套接字)
Post comment discussion:
发表评论讨论:
This code now demonstrates correct usage.
此代码现在演示了正确的用法。
采纳答案by ok2c
One needs to pro-actively evict expired / idle connections from the connection pool, as in the blocking I/O model connections cannot react to I/O events unlessthey are being read from / written to. For details see
需要主动从连接池中驱逐过期/空闲连接,因为在阻塞 I/O 模型中,连接无法对 I/O 事件做出反应,除非它们正在被读取/写入。详情见
http://hc.apache.org/httpcomponents-client-dev/tutorial/html/connmgmt.html#d4e631
http://hc.apache.org/httpcomponents-client-dev/tutorial/html/connmgmt.html#d4e631
回答by Chris Hagan
I've marked oleg's answer as correct, as it highlights an important usage point about HttpClient's connection pooling.
我已将 oleg 的答案标记为正确,因为它突出了有关 HttpClient 连接池的重要使用点。
To answer my specific original question, though, which was "Should I be trying to solve for 0 unused sockets or trying to maximize pooling?"
不过,要回答我的特定原始问题,即“我应该尝试解决 0 个未使用的套接字还是尝试最大化池化?”
Now that the pooling solution is in place and working correctly the application throughput has increased by about 150%. I attribute this to not having to renegotiate SSL and multiple handshakes, instead reusing persistent connections in accordance with HTTP 1.1.
现在,池化解决方案已就位并正常工作,应用程序吞吐量增加了约 150%。我将此归因于不必重新协商 SSL 和多次握手,而是根据 HTTP 1.1 重用持久连接。
It is definitely worth working to utilize pooling as intended, rather than trying to hack around with calling ThreadSafeClientConnManager.shutdown() after each request etcetera. If, on the other hand, you were calling arbitrary hosts and not reusing routes the way I am you might easily find that it becomes necessary to do that sort of hackery, as the JVM might surprise you with the long life of CLOSE_WAIT designated sockets if you're not garbage collecting very often.
按预期使用池绝对值得,而不是尝试在每个请求之后调用 ThreadSafeClientConnManager.shutdown() 等等。另一方面,如果您正在调用任意主机而不是像我一样重用路由,您可能会很容易发现有必要进行这种黑客攻击,因为 JVM 可能会对 CLOSE_WAIT 指定套接字的长寿命感到惊讶,如果你不经常收集垃圾。
回答by Andre
I had the same issue and solved it using the suggesting found here: here. The author touches on some TCP basics:
我遇到了同样的问题并使用此处找到的建议解决了它:here。作者触及了一些 TCP 基础知识:
When a TCP connection is about to close, its finalization is negotiated by both parties. Think of it as breaking a contract in a civilized manner. Both parties sign the paper and it's all good. In geek talk, this is done via the FIN/ACK messages. Party A sends a FIN message to indicate it wants to close the socket. Party B sends an ACK saying it received the message and is considering the demand. Party B then cleans up and sends a FIN to Party A. Party A responds with the ACK and everyone walks away.
The problem comes in when B doesn't send its FIN. A is kinda stuck waiting for it. It has initiated its finalization sequence and is waiting for the other party to do the same.
当一个 TCP 连接即将关闭时,它的最终确定由双方协商。将其视为以文明的方式破坏合同。双方在文件上签字,一切顺利。在 geek talk 中,这是通过 FIN/ACK 消息完成的。A 方发送 FIN 消息表示要关闭套接字。B 方发送 ACK 表示收到消息并正在考虑需求。然后 B 方清理并发送 FIN 给 A 方。A 方以 ACK 响应,然后所有人走开。
当 B 不发送其 FIN 时,问题就出现了。A有点卡在等待它。它已启动其最终确定序列,并正在等待另一方执行相同操作。
He then mentions RFC 2616, 14.10to suggest setting up an http header to solve this issue:
然后他提到RFC 2616, 14.10建议设置一个 http 标头来解决这个问题:
postMethod.addHeader("Connection", "close");
Honestly, I don't really know the implications of setting this header. But it did stop CLOSE_WAIT from happening on my unit tests.
老实说,我真的不知道设置这个标题的含义。但它确实阻止了 CLOSE_WAIT 在我的单元测试中发生。