首页 > 编程学习 > HTTP/2 牛逼在哪

HTTP/2 牛逼在哪

发布时间:2022/9/2 20:20:55

先说说 HTTP/ 1.1 协议的性能问题

原因:

  1. 延迟难以下降
  2. 并发连接有限
  3. 队头阻塞问题
  4. HTTP 头部巨大且重复
  5. 不支持服务器推送消息

HTTP/1.1自身采用的优化手段:

  • 将多张小图合并成一张大图供浏览器 JavaScript 来切割使用;
  • 将图片的二进制数据通过 base64 编码后,把编码数据嵌入到 HTML 或 CSS 文件中,以此来减少网络请求;
  • 将多个体积较小的 JavaScript 文件使用 webpack 等工具打包成一个体积更大的 JavaScript 文件,以一个请求替代多个请求;

同时也会带来一个问题:当某个 js 文件变化了,需要重新请求同一个包里的所有 js 文件。

  • 将同一个页面的资源分散到不同域名,提升并发连接上限,因为浏览器通常对通一域名的 HTTP 连接最大只能是 6 个。

尽管对 HTTP/1.1 协议的优化手段如此之多,但是效果还是不尽人意,因为这些手段都是对 HTTP/1.1 协议的“外 部”做优化。

兼容 HTTP/1.1

如何做到

  1. HTTP/2 没有在 URI 里引入新的协议名。
  2. 只在应用层做了改变,且还是基于 TCP 协议传输。

HTTP/2 把 HTTP 分 解成了「语义」和「语法」两个部分,「语义」层不做改动,与 HTTP/1.1 完全一致,如请求方法、状态码、头 字段等规则保留不变。

但是,HTTP/2 在「语法」层面做了很多改造,基本改变了 HTTP 报文的传输格式。

头部压缩

HTTP/2 使用了 HPACK 算法来对头部(called:Header)进行处理。

HPACK 算法

包含三部分:

  1. 静态字典
  2. 动态字典
  3. Huffman 编码(压缩算法)

实现过程:

客户端和服务器两端都会建立和维护【字典】(用长度较小的索引号表示重复的字符串),再用 Huffman 编码压缩数据,可达 50%~90% 的高压缩率。

静态字典(called:静态编码表)

HTTP/2 为高频出现在头部的字符串和字段建立了一张静态表(不会变化),共 61 组。

动态字典(called:动态编码表)

该表的 index 从 62 起步。

如,第一次发送时头部中的 【user-agent】字段数据有上百个字节,经过 Huffman 编码发送出去后,客户端和服务器双方都会更新自己的动态表,添加一个新的 index 号 62。那么在下一次发送的时候,就不用重复发这个字段的数据,只需要发 1 个字节的 index 号就行,因为双方都可以根据自己的动态表获取到字段的数据。

但是,动态表越大,占用的内存也就越大。也会影响服务器性能。

因此 Web 服务器都会提供类似 http2_max_request 的配置,用于限制一个连接上能够传输的请求数量,避免动态表无限增大,请求数量到达上限后,就会关闭 HTTP/2 连接来释放内存。

二进制帧

HTTP/2 将 HTTP/1 的文本格式改成二进制格式传输数据。

二进制数据使用 位运算 能高效解析。

具体细节:

帧类型:

HTTP/2 总共定义了 10 种类型的帧。分为数据帧和控制帧两类。

标志位:

用于携带简单的控制信息。(含:优先级......)

流标识符:

用来标识该 Frame 属于哪个 Stream。接收方可以据此从乱序的帧里找到相同Stream ID 的帧,从而有序组装信息。

故不同 Stream 的帧是可以乱序发送的。但同一 Stream 内部的帧必须是严格有序的。

帧数据:

存放的是通过 HPACK 算法压缩过的 HTTP 头部和包体。

并发传输

多个Stream 复用同一条 TCP 连接,达到并发的效果。

解决了 HTTP 层面的队头阻塞的问题。但仍存在 TCP 层面的队头阻塞问题。

具体细节:

由上图可知:

  • 1 个 TCP 连接包含一个或多个 Stream;
  • 1 个 Stream 里可包含 一个或多个 Message(content:请求或响应);
  • 1 个 Message 里可包含 一个或多个 Frame(content:一个或多个 TCP 报文);

谁可以建立 Stream

客户端和服务器双方都可以建立 Stream。

关于 Stream ID

  1. 客户端建立的 Stream 的 Stream ID 必须是奇数,服务器建立的必须是偶数。
  2. 同一个连接中的 Stream ID 是不能复用的,只能顺序递增。
  3. 当 ID 数耗尽时,需要发一个控制帧 【GOAWAY】来关闭 TCP 连接。

服务器主动推送资源

如何实现:

服务器在推送资源时,会通过【PUSH_PROMISE】帧传输 HTTP 头部,并通过帧中的 Promise Stream ID 字段告知客户端,接下来会在哪个偶数号 Stream 中发送包体。


仍存问题:HTTP/2 在 TCP 层面上的队头阻塞问题

HTTP/2 是基于 TCP 协议来传输数据的,TCP 是字节流协议,TCP 层必须保证收到的字节数据是完整且连续的, 这样内核才会将缓冲区里的数据返回给 HTTP 应用,那么当「前 1 个字节数据」没有到达时,后收到的字节数据只 能存放在内核缓冲区里,只有等到这 1 个字节数据到达时,HTTP/2 应用层才能从内核中拿到数据 。

Copyright © 2010-2022 mfbz.cn 版权所有 |关于我们| 联系方式|豫ICP备15888888号