第 15 题:简单讲解一下 http2 的多路复用
HTTP2 采用二进制格式传输,取代了 HTTP1.x 的文本格式,二进制格式解析更高效。
多路复用代替了 HTTP1.x 的序列和阻塞机制,所有的相同域名请求都通过同一个 TCP 连接并发完成。在 HTTP1.x 中,并发多个请求需要多个 TCP 连接,浏览器为了控制资源会有 6-8 个 TCP 连接都限制。
HTTP2 中
- 同域名下所有通信都在单个连接上完成,消除了因多个 TCP 连接而带来的延时和内存消耗。
- 单个连接上可以并行交错的请求和响应,之间互不干扰
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(26)
多路复用
所以 http/2 的多路复用属于 时分复用,频分复用,空分复用还是码分复用呢。。。。
http 2.0
HTTP2 采用二进制格式传输
相对于 HTTP1.x 的文本格式,二进制格式解析更高效。关键之一就是在应用层(HTTP/2)和传输层(TCP or UDP)之间增加一个二进制分帧层。
在二进制分帧层中, HTTP2 会将所有传输的信息分割为更小的消息和帧(frame),并对它们采用二进制格式的编码。
多路复用
代替了 HTTP1.x 的序列和阻塞机制,所有的相同域名请求都通过同一个 TCP 连接并发完成。在 HTTP1.x 中,并发多个请求需要多个 TCP 连接,浏览器为了控制资源会有 6-8 个 TCP 连接都限制。
HTTP2 中
Header Compression
HTTP2 使用了专门为首部压缩而设计的 HPACK 算法。
服务端推送(Server Push)
Reference
其实在某些情景下,多路复用(相比于多个连接)可能不会带来性能上的提升。
但是解决了绝大部分场景的问题
for example?
虽然http1.1默认开启了keep-alive, 使得tcp可以复用了, 但由于"队头阻塞(Head-of-line blocking)"的存在, 后面请求可能会由于前面的请求时长过长而阻塞; 因此浏览器在同时发出n条请求时, 会建立n条tcp连接(当然并不是无限制开启, 不然就和http1.0无区别了, 比如chrome是限制同一时刻最多六条), 当请求数超过n条时, 才会复用tcp连接;
假设我们统一使用chrome, 那每个人最大的建立的连接数为6;
当服务器设置了最大并发数为300, 最多可满足50个客户端(客户端建立最大连接数)同时访问服务器, 当第51个客户端访问时, 则需要排队~
如果同域名不同端口呢?也是一个连接吗
请教个问题,一个 HTTP2 消息被分成头部帧和数据帧之后,重新装配时,怎么知道这两个帧是属于同一个消息呢?流标识只能表示它们在同一个流里,但是一个流可以包含很多条消息,所以流标识是不能判断两个帧是否是同一个消息的,那么如何判断呢?
如果一个接扣即支持http1又支持http2, 前端发送请求时能决定使用的是http1版本还是http2版本么?
https://datatracker.ietf.org/doc/html/rfc7540. RFC的这一节有讲你说的问题。
在http2.0中,连接支持多路复用,但是后端如果在每个请求的响应头部中返回Connection为close,请问下该连接会关闭吗?
这个只是讲了头部帧分片后,如何重新装配的问题。我问的是重新装配时,怎么确定一个消息的头部帧和数据帧属于同一个消息
请问这个问题解决了吗? 查了很多资料都是泛泛而谈,没有具体细节
这个理论是真理论啊,有没有可观察可实现的?
有个疑惑,http2单个连接多路复用处理多个请求,请求个数也是有上限的吧?否则大量请求还会有堆积吧?
第二个问题里说到连接数过多?开了keep-alive怎么还连接数过多?复用了相同域名的连接,怎么还会过多呢?
在http1.1 中 默认允许 connect: keep-alive 但是在一个TCP里面 数据通信时按次进行,也就是说第二次请求发送要在第一次响应后进行,若第一次响应慢,则要一直阻塞。这个问题就是对头阻塞。
在HTTP/2.0中,在一个TCP链接中,客户端和服务器可以同时发送多个请求和响应,则避免了对头阻塞, 实现了 双向 实时 多工。 在2.0中 采用了数据流,对同一个请求或响应的所有数据包做了一个独一无二的标识,所以可以不用等待发送。两端会根据标识组装数据流。
上面说的都挺多了,我补充个header压缩吧,23333
这个在http 1.1中,jwt太大了真的是还不能压缩占据了很多带宽,2.0后可以压缩头部,还是很不错滴~
简单版回答:
HTTP/2 复用 TCP 连接,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应。
举例来说,在一个TCP连接里面,服务器同时收到了A请求和B请求,于是先回应A请求,结果发现处理过程非常耗时,于是就发送A请求已经处理好的部分, 接着回应B请求,完成后,再发送A请求剩下的部分。
历史原因解释:
1、HTTP/1.0 版本
该版本主要缺点是,每个TCP连接只能发送一个请求。发送数据完毕,连接就关闭,如果还要请求其他资源,就必须再新建一个连接。为了解决这个问题,需要使用
Connection: keep-alive
这个字段。2、HTTP/1.1 版本
该版本引入了持久连接(persistent connection),即 TCP 连接默认不关闭,可以被多个请求复用,不用声明 Connection: keep-alive。还引入了管道机制(pipelining),即在同一个TCP连接里面,客户端可以同时发送多个请求。这样就进一步改进了HTTP协议的效率。
虽然1.1版允许复用TCP连接,但是同一个TCP连接里面,所有的数据通信是按次序进行的。服务器只有处理完一个回应,才会进行下一个回应。要是前面的回应特别慢,后面就会有许多请求排队等着。这称为"队头堵塞"(Head-of-line blocking)。
HTTP/2.0 相比1.0有哪些重大改进
http/1.0:如需要发送多个请求必须创建多个 TCP 连接,并且浏览器对于单域名请求有数量限制(一般6个),其连接无法被复用
http/1.1:引入流水线(Pipelining)技术,但先天 FIFO(先进先出)机制导致当前请求的执行依赖于上一个请求执行的完成,容易引起报头阻塞,并没有从根本上解决问题
http/2:重新定义底层 http 语义映射,允许同一个连接上使用请求和响应双向数据流。同一域名只需占用一个 TCP 连接,通过数据流(Stream)以帧为基本协议单位,从根本上解决了问题,避免了因频繁创建连接产生的延迟,减少了内存消耗,提升了使用性能
资料:《koa 与 nodejs 开发实战》 http 篇
正常情况下一个http请求就会建立一个TCP连接,在这种情况下就不存在线头阻塞。但是当多个请求复用一个TCP连接时才可能出现这个问题。不同域名的请求当然不能共用一个TCP连接,而且就算是同一个域名下的请求,也要看服务器支不支持pipeline。即使服务器支持pipeline,也要根据自己的实际使用场景来决定要不要以pipeline的形式发送请求。
HTTP1.X的线头阻塞问题指的是统一域名下的请求会有阻塞问题吗?还是说页面的所有请求都必须按顺序相应
http/1中的每个请求都会建立一个单独的连接,除了在每次建立连接过程中的三次握手之外,还存在TCP的慢启动导致的传输速度低。其实大部分的http请求传送的数据都很小,就导致每一次请求基本上都没有达到正常的传输速度。
在http1.1中默认开启keep-alive,解决了上面说到的问题,但是http的传输形式是一问一答的形式,一个请求对应一个响应(http2中已经不成立,一个请求可以有多个响应,server push),在keep-alive中,必须等下上一个请求接受才能发起下一个请求,所以会收到前面请求的阻塞。
使用pipe-line可以连续发送一组没有相互依赖的请求而不比等到上一个请求先结束,看似pipe-line是个好东西,但是到目前为止我还没见过这种类型的连接,也间接说明这东西比较鸡肋。pipe-line依然没有解决阻塞的问题,因为请求响应的顺序必须和请求发送的顺序一致,如果中间有某个响应花了很长的时间,后面的响应就算已经完成了也要排队等阻塞的请求返回,这就是线头阻塞。
http2的多路复用就很好的解决了上面所提出的问题。http2的传输是基于二进制帧的。每一个TCP连接中承载了多个双向流通的流,每一个流都有一个独一无二的标识和优先级,而流就是由二进制帧组成的。二进制帧的头部信息会标识自己属于哪一个流,所以这些帧是可以交错传输,然后在接收端通过帧头的信息组装成完整的数据。这样就解决了线头阻塞的问题,同时也提高了网络速度的利用率。
简单来说, 就是在同一个TCP连接,同一时刻可以传输多个HTTP请求。
在 HTTP/1 中,每次请求都会建立一次HTTP连接,也就是我们常说的3次握手4次挥手,这个过程在一次请求过程中占用了相当长的时间,即使开启了 Keep-Alive ,解决了多次连接的问题,但是依然有两个效率上的问题:
HTTP/2的多路复用就是为了解决上述的两个性能问题。
在 HTTP/2 中,有两个非常重要的概念,分别是帧(frame)和流(stream)。
帧代表着最小的数据单位,每个帧会标识出该帧属于哪个流,流也就是多个帧组成的数据流。
多路复用,就是在一个 TCP 连接中可以存在多条流。换句话说,也就是可以发送多个请求,对端可以通过帧中的标识知道属于哪个请求。通过这个技术,可以避免 HTTP 旧版本中的队头阻塞问题,极大的提高传输性能。