[如何在上传时使用多路复用http2功能

问题描述 投票:0回答:2

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

而且Java有一个httpclient,它本身支持HTTP / 2协议,因此,鉴于我为自己的理解而尝试编写该代码。

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

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

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));
         }
     });
java file-upload http2 java-http-client
2个回答
3
投票

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

这通常是错误的假设。

丢弃具有多个HTTP / 1.1连接以便可以并行上传的情况。

然后我们有1个TCP连接,我们想比较HTTP / 1.1和HTTP / 2的上传。

在HTTP / 1.1中,请求将被依次[,因此,多次上载的结束时间取决于连接的带宽(忽略TCP慢启动)。

在HTTP / 2中,请求将通过多路复用

interleaved

。但是,需要发送的数据是相同的,因此,多次上载的结束时间再次取决于连接的带宽。在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差很多,我不会感到惊讶。 / 2将需要对服务器配置进行一些调整。

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

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

java.net.http.HttpClient将通过BodyPublisher提供的字节作为原始数据处理,没有任何解释。为了说明我的观点,无论使用HttpRequest.BodyPublishers::ofFile(Path)还是HttpRequest.BodyPublishers::ofByteArray(byte[])在语义上都是无关紧要的:更改只是获取将要传输到远程方的字节的方式。在文件上传的情况下-服务器可能希望请求主体将以某些方式进行格式化。它还可能期望某些特定的标头与请求一起发送(例如Content-Type等)。 HttpClient不会为您神奇地做到这一点。目前,API还没有提供开箱即用的功能。您将需要在调用者级别实现它。(有一个RFE登录用于调查对多部分/表单数据的支持,但尚未在API中实现https://bugs.openjdk.java.net/browse/JDK-8235761

0
投票
© www.soinside.com 2019 - 2024. All rights reserved.