为啥 HTTP/2 多路复用虽然 tcp 做同样的事情?

Posted

技术标签:

【中文标题】为啥 HTTP/2 多路复用虽然 tcp 做同样的事情?【英文标题】:Why HTTP/2 does multiplexing altough tcp does same thing?为什么 HTTP/2 多路复用虽然 tcp 做同样的事情? 【发布时间】:2018-07-08 18:38:59 【问题描述】:

据我所知,TCP 将消息分解为多个段。那么,为什么要在 HTTP2 上再次进行多路复用?复用两次有什么好处?

【问题讨论】:

TCP 在比 http 更低的级别上工作。这意味着 TCP 实现基于包的方法这一事实与协议级别无关或没有帮助。您仍然需要为每个请求设置新的连接。 因为 HTTP/1.1 请求阻塞了 TCP 连接:***.com/questions/36517829/… 【参考方案1】:

TCP 没有被多路复用。 TCP 只是一个有保证的消息流(即重新请求丢失的数据包,并且在发生这种情况时 TCP 流基本上被暂时阻塞)。

TCP,作为一种基于数据包的协议,如果更高级别的应用协议(例如 HTTP)允许发送多条消息,可以用于多路连接。不幸的是,HTTP/1.1 不允许这样做:一旦发送了 HTTP/1.1 消息,在该消息完全返回之前,不能在该连接上发送其他消息(忽略严重支持的流水线概念)。这意味着 HTTP/1.1 基本上是同步的,如果没有使用全部带宽并且其他 HTTP 消息排队,那么它会浪费任何可以用于底层 TCP 连接的额外容量。

为了解决这个问题,可以打开更多的 TCP 连接,这基本上允许 HTTP/1.1 像(有限的)多路复用协议一样行动。如果网络带宽被充分利用,那么这些额外的连接不会带来任何好处——事实上存在容量并且其他 TCP 连接没有被充分利用,这意味着这是有道理的。

因此 HTTP/2 在协议中添加了多路复用,以允许将单个 TCP 连接用于多个正在进行的 HTTP 请求。

它通过将基于文本的 HTTP/1.1 协议更改为基于数据包的二进制协议来实现这一点。这些可能看起来像 TCP 数据包,但实际上并不相关(就像说 TCP 与 IP 相似,因为它基于数据包并不相关)。将消息拆分为数据包实际上是允许多条消息同时传输的唯一方法。

HTTP/2 还添加了流的概念,以便数据包可以属于不同的请求 - TCP 没有这样的概念 - 这才是真正使 HTTP/2 多路复用的原因。

事实上,由于 TCP 不允许单独的、独立的流(即多路复用),并且因为它是有保证的,这实际上引入了一个新问题,即单个丢弃的 TCP 数据包会支撑所有该连接上的 HTTP/2 流,尽管实际上只有一个流应该受到影响,而其他流应该能够继续运行。在某些情况下,这甚至会使 HTTP/2 变慢。 Google 正在尝试从 TCP 迁移到 QUIC 来解决这个问题。

更多关于 HTTP/2 下多路复用的含义(以及为什么它是一个很好的改进!)在我的回答中:What does multiplexing mean in HTTP/2

【讨论】:

“HTTP/2 还添加了流的概念,以便数据包可以属于不同的请求——TCP 没有这样的概念——这才是真正使 HTTP/2 多路复用的原因。”你的意思是 HTTP/1.1 将单个 HTTP 消息(请求或响应)封装在单个 TCP 数据包中,HTTP/2 将多个 HTTP 消息封装在单个 TCP 数据包中? 不,我的意思是 TCP 没有将数据包标记为一个 HTTP 请求或另一个的概念。它只是一个数据包流。所以 HTTP/1.1 只是一串字符,它必须假设所有数据包都是针对请求 1 的,直到它看到魔术字符标志着请求 1 的结束 - 然后它假设一切都是针对请求 2 的,直到它看到结束请求 2。但是 HTTP/2 将每个请求拆分为多个帧,用请求 id 标记每个帧(以及流 id,但基本上是为请求创建流),因此您可以将这些帧混合起来,然后在另一端解开它们。 谢谢,我明白了。 HTTP/2 的根本改进是流并发(流的交织),这是通过将流新拆分为具有流标识符的帧来实现的。在 HTTP/1.1 中流并发是不可能的,因为流被分割成字符,所以没有流标识符。因此,HTTP/2 的新颖之处不是 pipelining(它已经在 HTTP/1.1 中可用,但在 Web 浏览器中没有得到广泛支持)也不是 multiplexing(它已经在 HTTP 中可用) /1.1,因为多路复用只是在单个连接上使用多个流)。 几乎,除了多路复用意味着并发。串行请求(即一个接一个但不中断其间的连接——通过 HTTP/1.1 中的 keepalive 功能实现)不是多路复用的。 TCP 提供了一个接一个的串行请求,并且根据原始问题,以及我的答案中的第一行不是多路复用。 我认为这取决于您对流的看法。如果您对 HTTP/1.1 和 HTTP/2 使用不同的流定义,即在 HTTP/2 中,您将流定义为单个消息(即帧序列),而在 HTTP/1.1 中,您将流定义为 all 消息(即消息序列),那么是的,HTTP/1.1 不使用多路复用,因为每个连接(通道)只有一个流(信号)。但是,如果您对 HTTP/1.1 和 HTTP/2 使用相同的定义,即您将流定义为两者的单个消息,那么 HTTP/1.1 确实使用多路复用,因为每个连接有多个流。【参考方案2】:

TCP 不进行多路复用。 TCP 段只是意味着(单个)流数据被分割成可以在 IP 数据包中发送的片段。每个 TCP 段只用一个流偏移(序列号)来标识,而不是用任何有用的方式来标识单独的流。 (我们将忽略很少用的紧急指针。)

所以要进行多路复用,您需要在 TCP 之上放置一些东西。 HTTP/2 的作用。

【讨论】:

【参考方案3】:

HTTP 和 HTTP/2 都是应用层协议,它们必须使用 TCP 等较低层协议才能在 Internet 上进行实际通信。 Internet 的协议一般是 TCP over IP over Ethernet。

看起来像这样:

如您所见,HTTP 位于 TCP 之上。 TCP下面是IP。互联网的主要协议之一。 IP 本身处理交换/多路复用的数据包。我认为这就是您可能会认为 TCP 是多路复用的,但事实并非如此。可以将 TCP 连接想象成一个没有人可以通过的单车道公路隧道。可以说它在每个方向都有一条车道。这就是 TCP 连接的样子。一条隧道,您将数据放在一端,然后以与进入的顺序相同的顺序从另一端出来。这就是 TCP。您可以看到没有多路复用。然而,TCP 确实提供了一个可靠的连接协议,其他协议可以建立在 HTTP 之上。可靠性对于 HTTP 至关重要。

HTTP 1.1 只是一个请求响应协议。但如您所知,它不是多路复用的。因此,一次只允许一个未完成的请求,并且必须一次将整个响应发送到每个请求。以前,浏览器通过创建多个到服务器的 TCP 连接(隧道)来发出更多请求,从而绕过了这个限制。

HTTP 2 实际上将数据再次拆分,并允许在一个连接上进行多路复用,因此不需要创建更多连接。这意味着服务器可以开始服务多个请求并多路复用响应,以便浏览器可以同时开始接收图像、页面和其他资源,而不是一次接收一个。

希望能说清楚。

【讨论】:

我不认为这是一个很好的问题答案,因为虽然它有一些很好的信息,但它侧重于更高级别的抽象,而不是 TCP 协议本身的功能。如果抽象是以低效方式做某事的唯一原因(即,如果不是因为抽象而存在使用协议的更有效方式),那么抽象是不好的,应该改变,并且可能早就改了。因此,恕我直言,一个好的答案应该关注为什么 TCP 分段不能进行多路复用,而不是呈现给更高级别的内容。 @Ove - 你说得对,那是废话。我已经从头开始重写了我的答案。

以上是关于为啥 HTTP/2 多路复用虽然 tcp 做同样的事情?的主要内容,如果未能解决你的问题,请参考以下文章

为啥使用多个连接进行 HTTP/2 多路复用演示?

TCP的多路复用和分解

为啥使用 HTTP/2 的应用只建立一个 TCP 连接?

WinHTTP over HTTP/2 多路复用

白话http2的多路复用

http2多路复用