为啥使用 HTTP/2 的应用只建立一个 TCP 连接?
Posted
技术标签:
【中文标题】为啥使用 HTTP/2 的应用只建立一个 TCP 连接?【英文标题】:Why does app using HTTP/2 only establish one TCP connection?为什么使用 HTTP/2 的应用只建立一个 TCP 连接? 【发布时间】:2021-08-05 19:08:52 【问题描述】:我了解 HTTP/2 多路复用解决了 HTTP/1.1 中的行头阻塞问题。但是,在 TCP 协议中仍然存在行头块。即使在应用层同时发送请求,消息仍然需要在 TCP 连接中一一发送。 我的问题是为什么使用 HTTP/2 的应用程序不建立多个 TCP 连接,以便 HTTP/2 复用不会在传输层(TCP 协议)受到限制? 我知道在 UDP(QUIC) 上使用 HTTP/2 可以避免这个问题。在这篇文章中,我将讨论基于 TCP 的 HTTP/2。 如果应用程序确实建立了多个 TCP 连接(如果我不知道这个实现已经存在)。请求如何在所有 TCP 连接之间拆分?
【问题讨论】:
“但是,在 TCP 协议中仍然存在线头块。” 您能详细说明一下您的意思吗?在发送数据包2之前不必确认收到数据包1,这就是数据包具有序列号的原因,因此它们可以在接收端按顺序组装。 假设 package1 在 TCP 连接中丢失。服务器端将阻塞等待丢失的 package1。在客户端,package1需要重新发送,package2需要等待package1重新发送。那么为什么不像 HTTP/1.1 那样使用多个 TCP 连接呢?还是受网卡带宽限制,使用HTTP2建立多个TCP连接没有多大帮助?(我只是猜测) “在客户端,package1需要重新发送,package2需要等待package1重新发送。”我觉得不是这样.同样,这就是序列号的用途。但我并不深入了解网络细节。我确实认为,如果建立多个连接会(或)有用,它会(或正在)完成。 您有多少条电线和路由器将您连接到互联网? 【参考方案1】:我的问题是为什么使用 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)如何处理这个问题进行了动画比较问题here.
【讨论】:
【参考方案2】:你是对的,这是 HTTP/2 和 TCP 的问题。问题是,TCP(根据最新的 RFC)几乎不能支持多路复用。这就是 QUIC 来救援的地方,也是它受到如此多关注的原因之一。通过为每个感兴趣的 HTTP 资源打开多个 TCP 连接来与 TCP 进行多路复用可能是一个有效的解决方案,但它存在一些问题。
-
建立多个 TCP 连接的开销很大(它们都需要建立与服务器的连接,例如 SYN/SYN-ACK/ACK)。
此外,每个此类连接都将从初始 CWND 值(通常为 10)开始,因此传输可能最终会变慢。
我认为这很重要:您可能需要所有资源才能成功(有意义地)加载网络请求。例如,考虑打开一个包含一些 html、CSS 和 JS 文件的网页。您可以打开 3 个单独的连接并单独请求所有这些,但您可能确实需要所有三个文件才能与页面进行任何有意义的交互。
如果 3. 由于某种原因不适用,您必须在应用层小心,因为资源可能以不同的顺序到达。
但是,有一个例外,我观察到不同的行为取决于您使用的浏览器。如果网站有网站图标,这是一个例外。向服务器发出初始请求时,您可能需要所有与网页相关的材料,但您并不真正关心是否收到了小标签预览图标(图标),并且您不希望任何损失阻止您与页面交互,如果这是唯一缺少的东西。
我看到我的 Firefox 有时会打开一个新连接来下载网站图标,而 chrome 似乎会在同一个连接上下载该连接和页面材料。实际上,我认为这只是一种实现选择,因为这是我能想到的唯一一个有用的边缘案例,但网站图标太小了,不太可能产生影响。
【讨论】:
假设一个网页是否包含数百个 png 文件。为了加载所有这些,以便我可以与网络交互。与其在一个 TCP 连接中请求所有这些请求,不如在多个连接中请求更有效?例如在 TCP conn1 中请求 png 0 - 30,在 TCP conn2 中请求 png 31 - 60...等。不同 TCP 连接之间的通信实现起来复杂吗? 正如我所说,取决于用例。对于此特定实例,您所描述的可能是更有效的情况。虽然,您必须再次考虑到 png 0-30 可能会在 之后 png 31-60 到达,此时您必须决定是否部分加载网页并异步加载它稍后随着物品到达或进行全面刷新。您描述的场景是高度假设的,可能假设 PNG 没有被压缩,但根据研究,平均页面大小约为 2MB。浏览器针对一般情况进行优化,而不是边缘情况。【参考方案3】:是的,这是 HTTP/2 的一个已知问题,也是 HTTP/3 旨在通过在同一连接中拥有完全独立的流来解决的问题。为此,他们不能使用 TCP,基本上必须从头开始构建 TCP 的多路复用版本(称为 QUIC)。
来自 Fastly 的 Hooman Beheshti 做了a great talk on this 并表明如果数据丢失率始终保持在 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-minute point of that above presentation)。
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 连接?的主要内容,如果未能解决你的问题,请参考以下文章