-
Notifications
You must be signed in to change notification settings - Fork 3.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
第 15 题:简单讲解一下 http2 的多路复用 #14
Comments
在 HTTP/1 中,每次请求都会建立一次HTTP连接,也就是我们常说的3次握手4次挥手,这个过程在一次请求过程中占用了相当长的时间,即使开启了 Keep-Alive ,解决了多次连接的问题,但是依然有两个效率上的问题:
HTTP/2的多路复用就是为了解决上述的两个性能问题。 |
简单来说, 就是在同一个TCP连接,同一时刻可以传输多个HTTP请求。
|
http/1中的每个请求都会建立一个单独的连接,除了在每次建立连接过程中的三次握手之外,还存在TCP的慢启动导致的传输速度低。其实大部分的http请求传送的数据都很小,就导致每一次请求基本上都没有达到正常的传输速度。 在http1.1中默认开启keep-alive,解决了上面说到的问题,但是http的传输形式是一问一答的形式,一个请求对应一个响应(http2中已经不成立,一个请求可以有多个响应,server push),在keep-alive中,必须等下上一个请求接受才能发起下一个请求,所以会收到前面请求的阻塞。 使用pipe-line可以连续发送一组没有相互依赖的请求而不比等到上一个请求先结束,看似pipe-line是个好东西,但是到目前为止我还没见过这种类型的连接,也间接说明这东西比较鸡肋。pipe-line依然没有解决阻塞的问题,因为请求响应的顺序必须和请求发送的顺序一致,如果中间有某个响应花了很长的时间,后面的响应就算已经完成了也要排队等阻塞的请求返回,这就是线头阻塞。 http2的多路复用就很好的解决了上面所提出的问题。http2的传输是基于二进制帧的。每一个TCP连接中承载了多个双向流通的流,每一个流都有一个独一无二的标识和优先级,而流就是由二进制帧组成的。二进制帧的头部信息会标识自己属于哪一个流,所以这些帧是可以交错传输,然后在接收端通过帧头的信息组装成完整的数据。这样就解决了线头阻塞的问题,同时也提高了网络速度的利用率。 |
HTTP1.X的线头阻塞问题指的是统一域名下的请求会有阻塞问题吗?还是说页面的所有请求都必须按顺序相应 |
正常情况下一个http请求就会建立一个TCP连接,在这种情况下就不存在线头阻塞。但是当多个请求复用一个TCP连接时才可能出现这个问题。不同域名的请求当然不能共用一个TCP连接,而且就算是同一个域名下的请求,也要看服务器支不支持pipeline。即使服务器支持pipeline,也要根据自己的实际使用场景来决定要不要以pipeline的形式发送请求。 |
http/1.0:如需要发送多个请求必须创建多个 TCP 连接,并且浏览器对于单域名请求有数量限制(一般6个),其连接无法被复用 http/1.1:引入流水线(Pipelining)技术,但先天 FIFO(先进先出)机制导致当前请求的执行依赖于上一个请求执行的完成,容易引起报头阻塞,并没有从根本上解决问题 http/2:重新定义底层 http 语义映射,允许同一个连接上使用请求和响应双向数据流。同一域名只需占用一个 TCP 连接,通过数据流(Stream)以帧为基本协议单位,从根本上解决了问题,避免了因频繁创建连接产生的延迟,减少了内存消耗,提升了使用性能 资料:《koa 与 nodejs 开发实战》 http 篇 |
简单版回答:HTTP/2 复用 TCP 连接,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应。 举例来说,在一个TCP连接里面,服务器同时收到了A请求和B请求,于是先回应A请求,结果发现处理过程非常耗时,于是就发送A请求已经处理好的部分, 接着回应B请求,完成后,再发送A请求剩下的部分。 历史原因解释:1、HTTP/1.0 版本该版本主要缺点是,每个TCP连接只能发送一个请求。发送数据完毕,连接就关闭,如果还要请求其他资源,就必须再新建一个连接。为了解决这个问题,需要使用 2、HTTP/1.1 版本该版本引入了持久连接(persistent connection),即 TCP 连接默认不关闭,可以被多个请求复用,不用声明 Connection: keep-alive。还引入了管道机制(pipelining),即在同一个TCP连接里面,客户端可以同时发送多个请求。这样就进一步改进了HTTP协议的效率。 虽然1.1版允许复用TCP连接,但是同一个TCP连接里面,所有的数据通信是按次序进行的。服务器只有处理完一个回应,才会进行下一个回应。要是前面的回应特别慢,后面就会有许多请求排队等着。这称为"队头堵塞"(Head-of-line blocking)。 |
在http1.1 中 默认允许 connect: keep-alive 但是在一个TCP里面 数据通信时按次进行,也就是说第二次请求发送要在第一次响应后进行,若第一次响应慢,则要一直阻塞。这个问题就是对头阻塞。 |
上面说的都挺多了,我补充个header压缩吧,23333 |
第二个问题里说到连接数过多?开了keep-alive怎么还连接数过多?复用了相同域名的连接,怎么还会过多呢? |
多路复用
|
所以 http/2 的多路复用属于 时分复用,频分复用,空分复用还是码分复用呢。。。。 |
其实在某些情景下,多路复用(相比于多个连接)可能不会带来性能上的提升。 |
for example? |
虽然http1.1默认开启了keep-alive, 使得tcp可以复用了, 但由于"队头阻塞(Head-of-line blocking)"的存在, 后面请求可能会由于前面的请求时长过长而阻塞; 因此浏览器在同时发出n条请求时, 会建立n条tcp连接(当然并不是无限制开启, 不然就和http1.0无区别了, 比如chrome是限制同一时刻最多六条), 当请求数超过n条时, 才会复用tcp连接; 假设我们统一使用chrome, 那每个人最大的建立的连接数为6; |
如果同域名不同端口呢?也是一个连接吗 |
请教个问题,一个 HTTP2 消息被分成头部帧和数据帧之后,重新装配时,怎么知道这两个帧是属于同一个消息呢?流标识只能表示它们在同一个流里,但是一个流可以包含很多条消息,所以流标识是不能判断两个帧是否是同一个消息的,那么如何判断呢? |
https://datatracker.ietf.org/doc/html/rfc7540#section-4.3. RFC的这一节有讲你说的问题。 |
在http2.0中,连接支持多路复用,但是后端如果在每个请求的响应头部中返回Connection为close,请问下该连接会关闭吗? |
这个只是讲了头部帧分片后,如何重新装配的问题。我问的是重新装配时,怎么确定一个消息的头部帧和数据帧属于同一个消息 |
请问这个问题解决了吗? 查了很多资料都是泛泛而谈,没有具体细节 |
这个理论是真理论啊,有没有可观察可实现的? |
有个疑惑,http2单个连接多路复用处理多个请求,请求个数也是有上限的吧?否则大量请求还会有堆积吧? |
面试八股:个人见解,欢迎大家指正qaq 首先,我认为 HTTP2 中的多路复用,属于是 时分复用,对同一个域名只建立一条连接,充分压榨 tcp 全双工的特性,存在两个流方向,流中并发传输数据帧,最后根据 流id, 帧id 以及控制位复原流,解决 http1.x 的对头堵塞问题,将单一请求的时延,转化成为多个请求的时延,降低用户对单一时延的感知。 |
如果是说服务端,那基本不太可能会有单个页面请求直接打到服务端上限的可能,集群扩展下抗成百上千qps都很简单; |
确实是这样,因为用单个tcp通道还是没有解决tcp层面的阻塞问题,导致丢包率上升;因此才有http3的出现 |
比如弱网情况下,因为一个域名只有一条连接,TCP头部阻塞会影响该帧流的所有请求 |
HTTP2采用二进制格式传输,取代了HTTP1.x的文本格式,二进制格式解析更高效。
多路复用代替了HTTP1.x的序列和阻塞机制,所有的相同域名请求都通过同一个TCP连接并发完成。在HTTP1.x中,并发多个请求需要多个TCP连接,浏览器为了控制资源会有6-8个TCP连接都限制。
HTTP2中
The text was updated successfully, but these errors were encountered: