HttpsServer使用curl导致CPU负载达到100%

4
我已经创建了一个围绕Java的HttpsServer的最小应用程序。
我安装了一个HttpHandler,它会回复一个短文本消息来响应请求:
return exchange -> {
    try {
        OutputStream responseBodyStream = exchange.getResponseBody();

        byte[] response = "Trouble with HTTPS and curl\n"
                .getBytes(StandardCharsets.UTF_8);

        exchange.getResponseHeaders().set("Content-Type", "text/plain");

        exchange.sendResponseHeaders(200, response.length);

        responseBodyStream.write(response);

        responseBodyStream.close();

        // Note that exchange.close() also closes the exchange's input stream
        // and output stream

    } catch (Exception e) {
        log.warn("Could not handle request", e);
    }
};

当使用curl连接服务器时,服务器会做出响应,但Java进程仍在使用整个核心,因此导致服务器无法响应。
正是这行代码引发了这个问题:
responseBodyStream.close();

如果我们移除这行代码,服务器仍然可以正常工作。
文档中得知:
为了正确终止每个交换,即使不发送响应主体,输出流也必须关闭。
我已经创建了一个项目来复现这个问题。
到目前为止,我发现了一些潜在的线索:
  • 只有使用curl连接服务器时才会出现高CPU使用率。使用Firefox连接时,CPU使用率保持较低
  • 当使用没有TLS的常规HTTP服务器时,不会出现此问题
  • 使用Flight Recorder收集的数据表明,HTTP-Dispatcher线程中的SSLEngineImpl#writeRecord分配了大量对象。

我正在使用Arch Linux 5.1.7操作系统,OpenJDK 12.0.1+12版本。curl的版本为7.65.1。

这是JDK的一个bug吗?还是我错误地使用了HttpsServer

1个回答

5
我也能复现这个问题。
SSLStreams.doClosure中有一个无限循环 - 这明显是JDK的bug。
HttpsServer在JDK 10中运行良好,但在JDK 11中开始循环。我猜测问题可能是HttpsServer实现没有适应出现在JDK 11中的TLS v1.3半关闭策略。
幸运的是,有一种解决方法。添加-Djdk.tls.acknowledgeCloseNotify=true JVM选项。使用此选项,HttpsServer将按预期工作。有关详细信息,请参见JDK-8208526

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接