HTTP/2优势分析

发布于:2024-03-28 ⋅ 阅读:(26) ⋅ 点赞:(0)
  • HTTP/1.1协议的性能问题

    • 最大性能问题就是 HTTP/1.1 的高延迟

    • 主要原因如下几个:

      • 延迟难以下降

      • 并发连接有限

      • 队头阻塞问题,;

      • HTTP 头部巨大且重复

      • 不支持服务器推送消息

    • 一些关键的地方是没办法优化的,比如请求-响应模型、头部巨大且重复、并发连接耗时、服务器不能主动推送等,要改变这些必须重新设计 HTTP 协议,于是 HTTP/2 就出来了

  • 兼容HTTP/1.1

    • HTTP/2 是怎么做的呢?

      • 第一点,HTTP/2 没有在 URI 里引入新的协议名,仍然用「http://」表示明文协议,用「https://」表示加密协议

      • 第二点,只在应用层做了改变,还是基于 TCP 协议传输,应用层方面为了保持功能上的兼容,HTTP/2 把 HTTP 分解成了「语义」和「语法」两个部分,「语义」层不做改动,与 HTTP/1.1 完全一致

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

  • 头部压缩

    • HTTP 协议的报文是由「Header + Body」构成的

    • HTTP/1.1 协议可以使用头字段 「Content-Encoding」指定 Body 的压缩方式,但报文中的另外一部分 Header,是没有针对它的优化手段。

    • HTTP/1.1 报文中 Header 部分存在的问题

      • 含很多固定的字段比如 Cookie、User Agent、Accept 等,有必要压缩

      • 大量的请求和响应的报文里有很多字段值都是重复的,必须要避免重复性

      • 字段是 ASCII 编码的,虽然易于人类观察,但效率低,所以有必要改成二进制编码

    • HTTP/2HPACK 算法压缩头部

    • HPACK 算法主要包含三个组成部分:

      • 静态字典;

      • 动态字典;

      • Huffman 编码(压缩算法);

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

    • 静态表编码

      • HTTP/2 为高频出现在头部的字符串和字段建立了一张静态表,它是写入到 HTTP/2 框架里的,不会变化的,静态表里共有 61

      • 表中的 Index 表示索引(Key),Header Value 表示索引对应的 Value,Header Name 表示字段的名字

      • HTTP/2 头部由于基于二进制编码,就不需要冒号空格和末尾的\r\n作为分隔符,于是改用表示字符串长度(Value Length)来分割 Index 和 Value。

    • 动态表编码

      • 静态表只包含了 61 种高频出现在头部的字符串,不在静态表范围内的头部字符串就要自行构建动态表,它的 Index 从 62 起步,会在编码解码的时候随时更新。

      • 那么在下一次发送的时候,就不用重复发这个字段的数据了,只用发 1 个字节的 Index 号就好了,因为双方都可以根据自己的动态表获取到字段的数据。

      • 使得动态表生效有一个前提:必须同一个连接上,重复传输完全相同的 HTTP 头部。

    • 二进制帧

      • HTTP/2 厉害的地方在于将 HTTP/1 的文本格式改成二进制格式传输数据,极大提高了 HTTP 传输效率,而且二进制数据使用位运算能高效解析

      • HTTP/2 把响应报文划分成了两类帧(Frame),图中的 HEADERS(首部) DATA(消息负载) 是帧的类型,也就是说一条 HTTP 响应,划分成了两类帧来传输,并且采用二进制来编码

      • 二进制帧的结构

        • 帧头(Frame Header)很小,只有 9 个字节,帧开头的前 3 个字节表示帧数据(Frame Playload)的长度。

        • 帧长度后面的一个字节是表示帧的类型,HTTP/2 总共定义了 10 种类型的帧,一般分为数据帧和控制帧两类,

        • 帧类型后面的一个字节是标志位,可以保存 8 个标志位,用于携带简单的控制信息

          • END_HEADERS 表示头数据结束标志,相当于 HTTP/1 里头后的空行(“\r\n”);

          • END_Stream 表示单方向数据发送结束,后续不会再有数据帧。

          • PRIORITY 表示流的优先级;

        • 帧头的最后 4 个字节是流标识符(Stream ID),但最高位被保留不用,只有 31 位可以使用,因此流标识符的最大值是 2^31,大约是 21 亿,它的作用是用来标识该 Frame 属于哪个 Stream,接收方可以根据这个信息从乱序的帧里找到相同 Stream ID 的帧,从而有序组装信息。

        • 帧数据了,它存放的是通过 HPACK 算法压缩过的 HTTP 头部和包体

    • 并发传输

      • HTTP/1.1 的实现是基于请求-响应模型的

      • 同一个连接中,HTTP 完成一个事务(请求与响应),才能处理下一个事务,也就是说在发出请求等待响应的过程中,是没办法做其他事情的,如果响应迟迟不来,那么后续的请求是无法发送的,也造成了队头阻塞的问题

      • HTTP/2 通过 Stream 这个设计,多个 Stream 复用一条 TCP 连接,达到并发的效果,解决了 HTTP/1.1 队头阻塞的问题,提高了 HTTP 传输的吞吐量。

        • 1 个 TCP 连接包含一个或者多个 Stream,Stream 是 HTTP/2 并发的关键技术;

        • Stream 里可以包含 1 个或多个 Message,Message 对应 HTTP/1 中的请求或响应,由 HTTP 头部和包体构成;

        • Message 里包含一条或者多个 Frame,Frame 是 HTTP/2 最小单位,以二进制压缩格式存放 HTTP/1 中的内容(头部和包体);

        • 多个 Stream 跑在一条 TCP 连接,同一个 HTTP 请求与响应是跑在同一个 Stream 中,HTTP 消息可以由多个 Frame 构成, 一个 Frame 可以由多个 TCP 报文构成。

      • 在 HTTP/2 连接上,不同 Stream 的帧是可以乱序发送的(因此可以并发不同的 Stream ),同一 Stream 内部的帧必须是严格有序的。

      • 因为当 HTTP/2 实现 100 个并发 Stream 时,只需要建立一次 TCP 连接,而 HTTP/1.1 需要建立 100 个 TCP 连接,每个 TCP 连接都要经过 TCP 握手、慢启动以及 TLS 握手过程,这些都是很耗时的。

      • HTTP/2 还可以对每个 Stream 设置不同优先级,帧头中的「标志位」可以设置优先级

    • 服务器主动推送资源

      • HTTP/1.1 不支持服务器主动推送资源给客户端,都是由客户端向服务器发起请求后,才能获取到服务器响应的资源。

      • 那 HTTP/2 的推送是怎么实现的?

        • 客户端发起的请求,必须使用的是奇数号 Stream,服务器主动的推送,使用的是偶数号 Stream。

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

        • 在 Stream 1 中通知客户端 CSS 资源即将到来,然后在 Stream 2 中发送 CSS 资源,注意 Stream 1 和 2 是可以并发的

    • 总结

      • HTTP/2优点

        • 第一点,对于常见的 HTTP 头部通过静态表和 Huffman 编码的方式,将体积压缩了近一半,而且针对后续的请求头部,还可以建立动态表,将体积压缩近 90%

        • 第二点,HTTP/2 实现了 Stream 并发,多个 Stream 只需复用 1 个 TCP 连接,节约了 TCP 和 TLS 握手时间,以及减少了 TCP 慢启动阶段对流量的影响

        • 第三点,服务器支持主动推送资源,大大提升了消息的传输性能

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

      • 有没有什么解决方案呢?

        • 放弃 TCP 协议,转而使用 UDP 协议作为传输层协议

本文含有隐藏内容,请 开通VIP 后查看