HTTP/2 和文件下载

Posted

技术标签:

【中文标题】HTTP/2 和文件下载【英文标题】:HTTP/2 & File Download 【发布时间】:2017-10-16 14:29:49 【问题描述】:

我们提供文件托管解决方案。我们的客户是最终用户,他们通过 HTTP 1.1 协议访问我们的服务器并下载文件。这些客户端基本上是软件系统或 CDN,它们使用软件库下载我们的文件。没有人类用户访问我们的系统。我们还提供了使用 HTTP/1.1 range-header 等进行部分文件下载的选项。客户端系统还通过使用多个线程跨块拆分来下载大文件。

我想检查如果我们向我们的服务器开放 HTTP/2.0 协议是否会有真正的好处?由于我们的客户端系统已经能够使用多线程来下载我们的文件,HTTP/2.0 多路复用会带来任何真正的好处吗?

谢谢

【问题讨论】:

【参考方案1】:

HTTP/2 文件下载比 HTTP/1.1 慢一些,主要原因有两个:帧开销和flow control。

在 HTTP/1.1 中,如果您使用 Content-Length 分隔下载,则下载的唯一字节是内容字节。 然而,在 HTTP/2 中,每个 DATA 帧为帧头携带 9 个额外字节。正常的最大帧大小为 16384 字节,这是一个很小的开销,但它存在。

可能导致速度变慢的更大原因是 HTTP/2 流控制。 客户端必须确保放大默认会话和流流控制窗口,默认均为 65535 字节。

HTTP/2 的工作方式是服务器为每个 HTTP/2 会话(连接)和该会话中的每个流保留一个 send 窗口。 当下载开始时,服务器有权仅发送发送窗口允许的字节数,用于该流或该会话,以先用完者为准。然后它必须等待客户端发送WINDOW_UPDATE 帧,补充流和会话流控制窗口,告诉服务器客户端已准备好接收更多数据。

对于像默认窗口这样的小窗口,由于客户端和服务器之间的网络延迟,这种机制可能会降低下载性能,特别是如果它是天真的实现的。 服务器大部分时间都会停顿等待客户端发送WINDOW_UPDATE,以便服务器可以发送更多数据。

多路复用起着双重作用。虽然它允许同时启动许多文件的下载(可能比 HTTP/1.1 更多的文件,这可能会受到它只能打开较少数量的连接的限制),但为每个流下载的数据也是如此有助于减少会话发送窗口。每个流可能仍然有一个未耗尽的发送窗口(因此它可以发送更多数据),但会话窗口已耗尽,因此服务器必须停止。流相互竞争以消耗会话发送窗口。服务器实现也很重要,因为它必须正确地交错来自多个流的帧。

话虽如此,但 HTTP/2 仍然有可能实现与 HTTP/1.1 的对等,前提是您对客户端和服务器都有相当高级的实现,并且您有足够的调整旋钮来控制关键的参数。

理想情况下,在客户端:

能够控制会话和流式传输初始流量控制窗口 一个很好的实现,在服务器还在下载的时候向服务器发送WINDOW_UPDATE帧,这样服务器就永远不会停顿;这可能需要根据 bandwidth-delay product 的自我调整功能(类似于 TCP 所做的)

理想情况下,在服务器上:

能够正确交织来自同一会话的多个流的帧(例如,避免先下载第一个流的所有帧,然后再下载第二个流的所有帧,等等,而是先下载第一个流的一个帧,然后一个帧第二个流的帧,然后是第一个流的一个帧,等等)

[免责声明,我是Jetty的HTTP/2维护者]

Jetty 9.4.x 支持上述所有功能,因为我们与社区和客户合作以确保尽可能快地下载 HTTP/2。

我们在服务器上实现了适当的交错,Jetty 的HttpClientHTTP2Client 分别提供了高级和低级API 来处理HTTP 和HTTP/2 请求。流控制在BufferingFlowControlStrategy 中实现,并允许在发送WINDOW_UPDATE 帧时进行调整(虽然还不是动态的)。 客户端还可以选择配置初始流量控制窗口。 Jetty 中的所有内容都是可插拔的,因此您可以编写更高级的流量控制策略。

即使您不使用 Java 或 Jetty,请务必剖析(或编写)您在客户端和服务器上使用的库,以便它们提供上述功能。

最后,您需要尝试和衡量;通过适当的 HTTP/2 实现和配置,多路复用效应应该发挥作用,从而增加并行性并减少客户端和服务器上的资源利用率,因此您将比 HTTP/1.1 更具优势。

【讨论】:

以上是关于HTTP/2 和文件下载的主要内容,如果未能解决你的问题,请参考以下文章

HTTP/2 下载速度比使用 HttpClient 的 HTTP/1.1 慢很多

nginx 服务页面取决于协议

【12-19】HTTP 2.0 和 HTTP1.1 区别

页面未完全加载文件并显示 net::ERR_HTTP2_PROTOCOL_ERROR

HTTP/2 服务器两次推送资产下载

HTTP/2 推送 JSON 负载