首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >状态CLOSE_WAIT与HttpClient的连接泄漏

状态CLOSE_WAIT与HttpClient的连接泄漏
EN

Stack Overflow用户
提问于 2019-03-20 22:37:40
回答 2查看 10.4K关注 0票数 11

我们使用JDK11 java.net.http HTTP从java.net.http获取数据。在我们收到响应后,连接仍然使用TCP状态CLOSE_WAIT打开在我们的服务器中,这意味着客户端必须关闭连接。

来自RFC 793术语:

关闭-等待-表示等待本地用户的连接终止请求.

这是我们的客户端代码,它以无状态REST的形式运行在Java12上的WildFly 16上。我们不明白为什么会这样。

代码语言:javascript
运行
复制
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpClient.Version;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;

public class SocketSandbox {

    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newBuilder().version(Version.HTTP_1_1).build();
        try (var listener = new ServerSocket(59090)) {
            System.out.println("Server is running...");
            while (true) {
                try (var socket = listener.accept()) {
                    HttpRequest request = HttpRequest
                            .newBuilder(URI.create("<remote_URL>"))
                            .header("content-type", "application/json").build();
                    HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
                    var out = new PrintWriter(socket.getOutputStream(), true);
                    out.println(String.format("Response HTTP status: %s", response.statusCode()));
                }
            }
        }
    }

}

我们得到“状态代码”,这意味着http响应被处理了。

当使用相同的代码调用其他端点时,连接是可以的。对于我们正在调用的远程API来说,这似乎是一个特殊的问题,但我们仍然不明白为什么Java客户端保持打开连接。

我们尝试了Windows和Linux机器,甚至在WildfFly之外都是独立的,但同样的结果也发生了。在每个请求之后,甚至从我们的无状态客户端执行该请求并接收响应后,每个请求都被保留为CLOSE_WAIT,并且永不关闭。

如果我们关闭Java进程,连接就会消失。

由HTTP客户端发送的标头:

代码语言:javascript
运行
复制
connection: 'Upgrade, HTTP2-Settings','content-length': '0',
host: 'localhost:3000', 'http2-settings': 'AAEAAEAAAAIAAAABAAMAAABkAAQBAAAAAAUAAEAA',
upgrade: 'h2c',
user-agent': 'Java-http-client/12'

服务器返回头部响应:Connection: close

最新情况(1)

我们尝试微调实现类jdk.internal.net.http.ConnectionPool中的池参数。

它没有解决这个问题。

代码语言:javascript
运行
复制
System.setProperty("jdk.httpclient.keepalive.timeout", "5"); // seconds
System.setProperty("jdk.httpclient.connectionPoolSize", "1");

最新情况(2)

使用Apache ,连接保持在CLOSE_WAIT状态大约90秒,但在那之后它能够连接。

调用方法HttpGet.releaseConnection()强制立即关闭连接。

代码语言:javascript
运行
复制
HttpClient client = HttpClients.createDefault();
HttpGet get = new HttpGet("https://<placeholderdomain>/api/incidents/list");
get.addHeader("content-type", "application/json");
HttpResponse response = client.execute(get);

// This right here did the trick
get.releaseConnection();

return response.getStatusLine().getStatusCode();

对于OkHttp客户端,它按预期的方式工作,没有连接卡住。

代码语言:javascript
运行
复制
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
        .url("https://<placeholderdomain>/grb/sb/incidentes/listar")
        .header("content-type", "application/json").build();
Response response = client.newCall(request).execute();
return response.body().string();

我们仍在努力寻找如何使它在java客户机中工作,这样我们就不必重写代码了。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-03-25 14:39:29

提交并确认为实现中的一个错误。

https://bugs.openjdk.java.net/browse/JDK-8221395

更新

检查JIRA问题,它在JDK 13中修复,并支持11.0.6。(不确定大约12)

票数 5
EN

Stack Overflow用户

发布于 2019-03-22 12:00:55

我不建议为每个新请求创建一个新客户端。这违背了HTTP/2的目的,HTTP/2允许在单个连接上复用请求。

第二件事是,这两个属性:

代码语言:javascript
运行
复制
System.setProperty("jdk.httpclient.keepalive.timeout", "5"); // seconds
System.setProperty("jdk.httpclient.connectionPoolSize", "1");

只适用于HTTP/1.1连接,而不是HTTP/2。还要注意,这些属性只在类加载时读取一次。因此,在加载java.net.http类之后设置它们不会有任何效果。

最后,在发布HttpClient之后,可能需要一段时间才能关闭所有保持活动的连接--这样做的内部机制基本上依赖于GC --这对于短暂的HttpClients来说并不是很友好。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55271192

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档