HTTP/2 文件下载比 HTTP/1.1 慢一点,主要原因有两个:帧开销和流量控制.
在 HTTP/1.1 中,如果您使用Content-Length
分隔下载,下载的唯一字节是内容字节。
然而,在 HTTP/2 中,每个DATA
帧携带 9 个额外字节作为帧头。对于 16384 字节的正常最大帧大小,这是一个很小的开销,但它确实存在。
可能导致速度变慢的更大因素是 HTTP/2 流量控制。
客户端必须确保扩大默认会话和流控制窗口,默认情况下均为 65535 字节。
HTTP/2 的工作方式是服务器保存一个send每个 HTTP/2 会话(连接)以及该会话中每个流的窗口。
当下载开始时,服务器有权为该流或该会话仅发送发送窗口允许的字节数,以先耗尽者为准。然后就必须等待客户端发送WINDOW_UPDATE
帧,补充流和会话流控制窗口,告诉服务器客户端已准备好接收更多数据。
对于像默认窗口这样的小窗口,这种机制可能会由于客户端和服务器之间的网络延迟而降低下载性能,特别是如果它是简单实现的。
服务器大部分时间都会停止等待客户端发送数据WINDOW_UPDATE
以便服务器可以发送更多数据。
多路复用起着双重作用。虽然它允许同时启动许多文件的下载(可能比 HTTP/1.1 更多的文件,这可能受到它只能打开较少数量的连接的限制),但为每个流下载的数据也是事实有助于减少会话发送窗口。每个流可能仍然有一个未耗尽的发送窗口(因此它可以发送更多数据),但会话窗口已耗尽,因此服务器必须停止。流相互竞争以消耗会话发送窗口。服务器实现也很重要,因为它必须正确地交错来自多个流的帧。
话虽如此,HTTP/2 仍然有可能实现与 HTTP/1.1 的同等水平,前提是您对客户端和服务器都有相当先进的实现,并且您有足够的调节旋钮来控制关键参数。
理想情况下,在客户端:
- 控制会话和流初始流量控制窗口的能力
- 一个好的实现发送
WINDOW_UPDATE
当服务器还在下载时向服务器发送帧,这样服务器就不会停止;这可能需要自调整功能,具体取决于带宽延迟积(类似于TCP的做法)
理想情况下,在服务器上:
- 正确交错来自同一会话的多个流的帧的能力(例如,避免下载第一个流的所有帧,然后下载第二个流的所有帧等,而是先下载第一个流的一帧,然后下载第二个流的一帧)第二个流,然后是第一个流的一帧,等等)
[免责声明,我是 HTTP/2 的维护者Jetty]
Jetty 9.4.x 支持上述所有功能,因为我们与社区和客户合作以确保 HTTP/2 下载尽可能快。
我们在服务器和 Jetty 上实现了适当的交错HttpClient
and HTTP2Client
分别提供高层和低层API来处理HTTP和HTTP/2请求。流量控制是在BufferingFlowControlStrategy并允许调整何时WINDOW_UPDATE
帧已发送(尽管尚未动态发送)。
客户端还可以选择配置初始流量控制窗口。
Jetty 中的所有内容都是可插拔的,因此您可以编写更高级的流量控制策略。
即使您不使用 Java 或 Jetty,也请确保剖析(或编写)您在客户端和服务器上使用的库,以便它们提供上述功能。
最后,你需要尝试和衡量;通过正确的 HTTP/2 实现和配置,多路复用效果应该发挥作用,从而提高并行性并减少客户端和服务器上的资源利用率,这样您将比 HTTP/1.1 具有优势。