gpt4 book ai didi

java - 上传时如何使用多路复用http2功能

转载 作者:行者123 更新时间:2023-12-01 19:29:49 28 4
gpt4 key购买 nike

上传多个文件时,使用多路复用 http2 功能应该会显着提高性能。

Java 有一个 httpclient,它本身支持 HTTP/2 协议(protocol),因此考虑到我尝试根据自己的理解编写代码。

这个任务似乎并不像我最初想象的那么容易,或者在另一方面,我似乎无法找到能够在上传中使用多路复用的服务器(如果存在)。

这是我写的代码,有人有想法吗?

HttpClient httpClient = HttpClient.newBuilder().version(HttpClient.Version.HTTP_2).build();
String url = "https://your-own-http2-server.com/incoming-files/%s";
Path basePath = Path.of("/path/to/directory/where/is/a/bunch/of/jpgs");

Function<Path, CompletableFuture<HttpResponse<String>>> handleFile = file -> {
String currentUrl = String.format(url, file.getFileName().toString());
try {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(currentUrl))
.header("Content-Type", "image/jpeg")
.PUT(HttpRequest.BodyPublishers.ofFile(file))
.build();
return httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString());
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
};

List<Path> files = Files.list(basePath).collect(toList());

files.parallelStream().map(handleFile).forEach(c -> {
try {
final HttpResponse<String> response = c.get();
System.out.println(response.statusCode());
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException((e));
}
});

最佳答案

There should be a significant improvement of performance using multiplexing http2 feature when uploading multiple files.

这种假设通常是错误的。

让我们放弃有多个 HTTP/1.1 连接的情况,以便可以并行上传。

然后我们有 1 个 TCP 连接,我们想要将上传与 HTTP/1.1 和 HTTP/2 进行比较。

在 HTTP/1.1 中,请求会被一个接一个地序列化,因此多次上传的结束时间取决于连接的带宽(忽略 TCP 慢启动)。

在 HTTP/2 中,请求将通过多路复用方式交错。但是,需要发送的数据是相同的,因此多次上传的结束时间同样取决于连接的带宽。

在 HTTP/1.1 中,您将拥有 upload1.start...upload1.end|upload2.start...upload2.end|upload3.start...upload3.end等等

在 HTTP/2 中,您将拥有 upload1.start|upload2.start|upload3.start.....upload3.end..upload1.end..upload2.end

结束时间是相同的。

HTTP/2 的问题在于,您通常不受连接带宽的限制,而是受 HTTP/2 流量控制窗口的限制,该窗口通常要小得多。

HTTP/2 规范默认 HTTP/2 流量控制窗口为 65535 字节,这意味着每 65535 字节客户端必须停止发送数据,直到服务器确认这些字节。这可能需要一个往返,因此即使对于大文件上传来说往返很短(例如 50 毫秒),您也可能会多次支付此往返费用,从而增加上传的时间(例如,对于 6 MiB 的上传,您可能需要支付 100 秒)次,即 5 秒)。

为服务器配置一个大的 HTTP/2 流量控制窗口非常重要,特别是当您的服务器用于文件上传时。服务器上的大 HTTP/2 流量控制窗口意味着服务器必须准备好缓冲大量字节,这意味着主要处理文件上传的 HTTP/2 服务器将需要比 HTTP/1.1 服务器更多的内存。

使用更大的 HTTP/2 流量控制窗口,服务器可能会变得智能,并在客户端仍在上传时向客户端发送确认。

当客户端上传时,它会缩小其“发送”窗口。通过接收来自服务器的确认,客户端放大“发送”窗口。

典型的不良交互是,指示客户端“发送”窗口值,从 1 MiB 开始:

[client send window]

1048576
client sends 262144 bytes
786432
client sends 262144 bytes
524288
client sends 262144 bytes
262144
client sends 262144 bytes
0
client cannot send
.
. (stalled)
.
client receives acknowledgment from server (524288 bytes)
524288
client sends 262144 bytes
262144
client sends 262144 bytes
0
client cannot send
.
. (stalled)
.

良好的互动是:

[client send window]

1048576
client sends 262144 bytes
786432
client sends 262144 bytes
524288
client sends 262144 bytes
262144
client receives acknowledgment from server (524288 bytes)
786432
client sends 262144 bytes
524288
client sends 262144 bytes
262144
client receives acknowledgment from server (524288 bytes)
786432

正如您在良好的交互中看到的,服务器在客户端耗尽“发送”窗口之前确认客户端,因此客户端可以继续全速发送。

多路复用对于许多小型请求确实很有效,这是浏览器用例:许多小型 GET 请求(没有请求内容)可以在 HTTP/2 中多路复用,比相应的 HTTP/1.1 更早到达服务器请求,因此将更早提供服务并更早返回浏览器。

对于大型请求,就像文件上传的情况一样,HTTP/2 可以与 HTTP/1.1 一样高效,但如果服务器的默认配置使其性能远低于 HTTP/1.1,我不会感到惊讶 - HTTP/2 需要对服务器配置进行一些调整。

HTTP/2 流量控制窗口也可能会妨碍下载,因此通过 HTTP/2 从服务器下载大型内容可能会非常慢(出于与上述相同的原因)。

浏览器通过告诉服务器让服务器“发送”窗口非常大来避免此问题 - Firefox 72 将其设置为每个连接 12 MiB,并且非常智能地确认服务器,以便它不会停止下载。

关于java - 上传时如何使用多路复用http2功能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60098299/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com