HttpsServer 使用 curl 导致 100% 的 CPU 负载



我围绕Java的HttpsServer创建了一个最小的应用程序。

我安装了一个HttpHandler,它通过短信回复请求:

return exchange -> {
try {
OutputStream responseBodyStream = exchange.getResponseBody();
byte[] response = "Trouble with HTTPS and curln"
.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 服务器时,curl 不会出现此问题
  • 使用飞行记录器收集的数据表明线程HTTP-Dispatcher中的SSLEngineImpl#writeRecord分配了许多对象

我在使用 OpenJDK 12.0.1+12 的 Arch Linux 5.1.7 上。curl 的版本是 7.65.1。

这是JDK中的错误吗?还是我用错了HttpsServer

我也可以重现这个问题。
SSLStreams.doClosure中有一个无限循环 - 这绝对是一个 JDK 错误。

HttpsServer 在 JDK 10 中运行良好,但在 JDK 11 中开始循环。我想问题是 HttpsServer 实现没有适应 TLS v1.3 半关闭策略出现在 JDK 11 中。

幸运的是,有一个解决方法。添加-Djdk.tls.acknowledgeCloseNotify=trueJVM 选项。使用此选项,HttpsServer 将按预期工作。有关详细信息,请参阅 JDK-8208526。

最新更新