ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

HTTP/2 牛逼在哪

2022-09-02 20:32:41  阅读:181  来源: 互联网

标签:HTTP 1.1 Stream TCP 服务器 字节


先说说 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 应用层才能从内核中拿到数据 。

标签:HTTP,1.1,Stream,TCP,服务器,字节
来源: https://www.cnblogs.com/tiddler/p/16651121.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有