http2的特性;多路复用怎么实现;和长链接的区别

2022-03-01  本文已影响0人  前端小白的摸爬滚打

http2 的特性

什么是多路复用?

就是一个连接上可以同时传输多个请求&响应(下一个请求不需要等前一个响应返回后再发出;对于响应服务器可以先处理完哪个就返回哪个而不需要按次请求的顺序返回)。

和长链接的区别?

首先讲一点:浏览器对于同一时间同一域名下的连接数有限制,一般是 4-8 个,Chrome 是 6 个。超过限制的数目会被阻塞。HTTP 允许客户端打开多条连接,并行地执行多个 HTTP 事务。

这就是为什么有些站点会有多个静态资源 CDN 域名的原因之一,变相的解决浏览器针对同一域名连接的限制阻塞问题。

http1.1 提出支持长链接和管道化。

长链接:即可以在一个 http 连接上传输多个请求&响应(http1.1 之前每个 http 链接只可以传输一对请求&响应然后就断开链接)。 在没有管道化的情况下,一个连接上的下一个请求需要在前一个响应返回后再发出。(并发请求只能通过同时建立多个连接实现)

问题:

管道化

问题:

Connection: keep-alive 声明一个链接是长链接

问:那么在 http1.1 中我们如何实现并发请求?

答:实现并发请求的唯一办法就是利用多个持久连接。可以发现在 HTTP1.1 中存在一些局限,它严格串行的返回响应,它不允许多个数据交错到达(多路复用),只能等待一个响应完全返回后,下一个响应才能发送,无论下一个响应是否早于前一个响应完成处理,这也叫做队首阻塞。这就带来一个非常糟糕的体验,如果第一个请求需要处理的时间非常长,那么后续的请求即使被服务器已经处理完成,响应也不能立即返回,而是存储在服务端的缓存区中,等待第一个响应的完成,才能按照 FIFO 顺序返回。

实际上,一些支持管道的浏览器,通常都将其作为一个高级配置选项,但大多数浏览器都会禁用它。换句话说,作为前端工程师,开发的应用是面向普通浏览器应用的话,还是不要过多的指望 HTTP 管道

结论:所以即使是 http1.1,我们也无法充分的利用其优势,如果需要同时并行发送请求还是要建立多个连接来实现。HTTP 持久连接虽然帮我们解决了 TCP 连接复用的问题,但是现阶段的 HTTP 管道却无法实现多个请求结果的交错返回,所以浏览器只能开启多个 TCP 连接,以达到并行地加载资源的目的。

多路复用

通过单一的 HTTP/2 连接发起多重的请求-响应消息,即在一个连接里,客户端和浏览器都可以同时发送多个请求和响应,而不用按照顺序一一对应,这样避免了“队头堵塞”。(服务器可以处理完就可以直接返回)很好地解决了浏览器限制同一个域名下连接数量的问题。

区别

多路复用怎么实现?

在 http2 中:

多路复用,就是在一个 TCP 连接中可以存在多条流。换句话说,也就是可以发送多个请求,对端可以通过帧中的标识知道属于哪个请求。通过这个技术,可以避免 HTTP 旧版本中的队头阻塞问题,极大的提高传输性能。

在 HTTP/2 中,有两个非常重要的概念,分别是帧(frame)和流(stream)

帧代表着最小的数据单位,实现了对消息的封装。每个帧会标识出该帧属于哪个流,流也就是多个帧组成的数据流。

帧的字节中保存了不同的信息,前 9 个字节对于每个帧都是一致的,“服务器”解析 HTTP/2 的数据帧时只需要解析这些字节,就能准确的知道整个帧期望多少字节数来进行处理信息。

名称 长度 描述
Length 3 字节 表示帧负载的长度
Type 1 字节 帧的类型
Flags 1 字节 具体帧的标识
R 1 字节 保留位,不需要设置,否则可能带来严重后果
Stream Identifier 31 位(约 4 字节) 每个流的唯一 ID
Frame Payload 不固定 是主体内容,由帧类型决定

为了能够发送不同的“数据信息”,通过帧数据传递不同的内容,HTTP/2 中定义了 10 种不同类型的帧,在上面表格的 Type 字段中可对“帧”类型进行设置。

HTTP/2 连接上独立的、双向的帧序列交换。流 ID(帧首部的 6-9 字节)用来标识帧所属的流。

流可以承载双向消息,每个流都有一个唯一的整数 ID。 HTTP/2 长连接中的数据包是不按请求-响应顺序发送的,一个完整的请求或响应(称一个数据流 stream,每个数据流都有一个独一无二的编号)可能会分成非连续多次发送。它具有如下几个特点:

在一条 Connection 中,不同的流可以穿插传递,但是同一条流的达到顺序必须是有序的,比如 1 号流,流内的 帧必须有序。

这就是传输中无序,接收时组装。

拓展

为什么限制并发连接数?

HTTP2 缺点

http 层面的对头阻塞

HTTP 层面的队头阻塞在于,HTTP/1.1 协议中同一个 TCP 连接中的多个 HTTP 请求只能按顺序处理,方式有两种标准,非管道化和管道化两种,非管道化方式:即串行执行,请求 1 发送并响应完成后才会发送请求 2,一但前面的请求卡住,后面的请求就被阻塞了;管道化方式:即请求可以并行发出,但是响应也必须串行返回(只提出过标准,没有真正应用过)。

TCP 层面的对头阻塞

TCP 层面的队头阻塞在于,TCP 本身不知道传输的是 HTTP 请求,TCP 只负责传递数据,传递数据的过程中会将数据分包,由于网络本身是不可靠的,TCP 传输过程中,当存在数据包丢失的情况时,顺序排在丢失的数据包之后的数据包即使先被接收也不会进行处理,只会将其保存在接收缓冲区中,为了保证分包数据最终能完整拼接成可用数据,所丢失的数据包会被重新发送,待重传副本被接收之后再按照正确的顺序处理它以及它后面的数据包。

But,由于 TCP 的握手协议存在,TCP 相对比较可靠,TCP 层面的丢包现象比较少见,需要明确的是,TCP 队头阻塞是真实存在的,但是对 Web 性能的影响比 HTTP 层面队头阻塞小得多,因此 HTTP/2 的性能提升还是很有作用的。

为什么 HTTP/1.1 不能实现“多路复用”?

简单回答就是:HTTP/2 是基于二进制“帧”的协议,HTTP/1.1 是基于“文本分割”解析的协议。

HTTP/1.1 发送请求消息的文本格式:以换行符分割每一条 key:value 的内容,解析这种数据用不着什么高科技,相反的,解析这种数据往往速度慢且容易出错。“服务端”需要不断的读入字节,直到遇到分隔符(这里指换行符,代码中可能使用/n 或者/r/n 表示)

一次只能处理一个请求或响应,因为这种以分隔符分割消息的数据,在完成之前不能停止解析。

上一篇 下一篇

猜你喜欢

热点阅读