我了解 HTTP/2 多路复用解决了 HTTP/1.1 中的线头阻塞问题。但是,在 TCP 协议中仍然存在行头块。即使在应用层同时发送请求,消息仍然需要在 TCP 连接中一一发送。
我的问题是为什么使用 HTTP/2 的应用程序不建立多个 TCP 连接,以便 HTTP/2 复用不会在传输层(TCP 协议)受到限制?
我知道在 UDP(QUIC) 上使用 HTTP/2 可以避免这个问题。在这篇文章中,我将讨论基于 TCP 的 HTTP/2。
如果应用程序确实建立了多个 TCP 连接(如果我不知道这个实现已经存在)。请求如何在所有 TCP 连接中拆分?
3 回答
我的问题是为什么使用 HTTP/2 的应用程序不建立多个 TCP 连接,以便 HTTP/2 复用不会在传输层(TCP 协议)受到限制?
这正是您在 HTTP/1.1 中已经可以做的事情,方法是设置一些持久的并行连接,您可以在这些连接上按顺序请求多个文件。
但是您建立的每个连接都需要建立 TCP 握手。假设站点通过 HTTPS 运行,除此之外还需要 TLS 握手。这是一个很大的宣传。
HTTP/2 通过只需要一次 TCP+TLS 握手来避免上述大张旗鼓,但正如您所提到的,它仍然是应用层上的“伪造”并行性。因此,如果您通过两个流传输并且流 1 出现问题,则流 2 无法继续传输,直到 TCP 解决了流 1 的问题。QUIC 为传输层上的并行流提供支持,因此它不会遇到同样的线头阻塞问题。
tl;dr – 如果这太抽象或难以理解,我在这里对 HTTP/1.1、HTTP/2 和 HTTP/3(使用 QUIC)如何处理这个问题进行了动画比较。
是的,这是 HTTP/2 的一个已知问题,也是 HTTP/3 旨在通过在同一连接中拥有完全独立的流来解决的问题。为此,他们不能使用 TCP,并且必须从头开始构建 TCP 的多路复用版本(称为 QUIC)。
来自 Fastly 的 Hooman Beheshti 对此进行了精彩的演讲,并表明如果始终有 2% 的数据丢失,您最好使用 HTTP/1.1。
那么我们应该怎么做呢?完全不使用 HTTP/2 并坚持使用 HTTP/1.1?或者,正如您建议的那样,将 HTTP/2 与多个连接一起使用。
好吧,首先您需要意识到,在大多数连接上,数据丢失,或者至少一致的数据丢失实际上是相对罕见的。根据那次谈话,持续 2% 的数据丢失基本上是一个糟糕的连接!数据丢失更加间歇性和突发性(例如,当您离开移动接收,然后又回来时)。
HTTP/2 发布之前的研究表明,在大多数情况下,HTTP/2 比 HTTP/1.1 更好 - 或者至少实现良好的 HTTP/2 设置的机会会更快。
是的,事后看来,HTTP/2 被夸大了,而且优化良好的 HTTP/1.1 站点的收益通常相对较小。是的,在某些情况下它也可能更糟(特别是如果服务器不正确支持优先级)。但这在发布之前就已为人所知,而且总的来说 HTTP/2 更好并被推荐。
在某些情况下,就像您给出的那样,它的表现可能会更差。如果您的特定应用程序预计会出现严重损失(我不知道,假设您正在做一个经常在地下深处的矿井中使用的移动应用程序并且连接来来去去),那么也许不要使用 HTTP/2 并在这种情况下使用更好的协议(可能包括 HTTP/1.1)。但是对于一般的网页浏览来说,HTTP/2 在大多数情况下可能会更好。
那么为什么我们不使用具有多个连接的 HTTP/2 呢?
那么 HTTP/2 的主要好处是更好地利用了那个单一的连接。HTTP 连接设置(尤其是 HTTPS)很昂贵 - 您需要 TCP 握手、TLS 握手然后发出请求。即使在那之后,您也必须通过 TCP 慢启动才能使连接达到全速。如果连接没有被充分利用,那么它会再次变慢,你需要再次重复这个慢启动方法。
使用单个连接意味着您只需支付一次设置价格,并且意味着您不太可能使连接未充分利用,因此退回到较慢的连接速度并不得不再次经历 TCP 慢启动。此外,您可以在单个连接上交叉优先级请求。如果您有一些关键的 CSS 和一些较低优先级的图像或异步 JavaScript 也在运行中,服务器可以优先考虑 CSS 并为此使用带宽并阻止图像和异步 JavaScript(尽管同样并非所有服务器都很好地实现了 HTTP/2 优先级)。使用独立的连接,跨不同请求的优先级是不可能的,因此您最终会低效地使用带宽。
然而,有些人建议,在有损连接上,即使在 HTTP/2 下,我们也应该切换回两个甚至更多连接(参见上面演示文稿的 22 分钟点)。
HTTP/2 也是向 HTTP/3 迈出的一步(尽管最初将被称为 HTTP/2 over QUIC)。向 HTTP/2 的迁移是 Web 核心协议之一的工作方式的一大步和重大变化。从开发人员的角度来看,在 HTTP/2 下不需要捆绑太多(尽管完全删除捆绑太远)的心态转换是 HTTP/2 附带的,并且在 HTTP/3 下不会改变. HTTP/2 于 2015 年签署,它的继任者 HTTP/3 花了 6 年时间才出现并解决了这个问题,它是一个复杂得多的协议,最初为这种复杂性带来的好处要少得多。为您的服务器运行 HTTP/3 并以最佳方式对其进行优化将变得更加困难。
因此,推迟使用希望通过 HTTP/3 交付的完整解决方案,而不是继续使用 HTTP/2,将是错误的调用。并且使用多个 HTTP/2 连接也有它的缺点。
希望这能回答你的问题。
你是对的,这是 HTTP/2 和 TCP 的问题。问题是,TCP(根据最新的 RFC)几乎不能支持多路复用。这就是 QUIC 来救援的地方,也是它受到如此多关注的原因之一。通过为每个感兴趣的 HTTP 资源打开多个 TCP 连接来与 TCP 进行多路复用可能是一个有效的解决方案,但它存在一些问题。
- 建立多个 TCP 连接有很大的开销(它们都需要建立到服务器的连接,例如 SYN/SYN-ACK/ACK)。
- 此外,每个此类连接都将从初始 CWND 值(通常为 10)开始,因此传输可能最终会变慢。
- 我认为这很重要:您可能需要所有资源才能成功(有意义地)加载 Web 请求。例如,考虑打开一个包含一些 HTML、CSS 和 JS 文件的网页。您可以打开 3 个单独的连接并单独请求所有这些,但很可能您确实需要所有三个文件才能与页面进行任何有意义的交互。
- 如果 3. 由于某种原因不适用,您将不得不在应用层小心,因为资源可能以不同的顺序到达。
但是,有一个例外,我观察到不同的行为取决于您使用的浏览器。如果网站有网站图标,这是一个例外。在向服务器发出初始请求时,您可能需要所有与网页相关的材料,但您并不真正关心是否收到了小标签预览图标(图标),并且您不希望任何损失阻止您与页面交互,如果这是唯一缺少的东西。
我看到我的 Firefox 有时会打开一个新连接来下载网站图标,而 chrome 似乎会在同一个连接上下载该连接和页面材料。实际上,我认为这只是一种实现选择,因为这是我能想到的唯一一种边缘情况,它在哪里有用,但网站图标太小了,不太可能产生影响。