计算机网络 ---- HTTP/1.1HTTP/2HTTP/3演变过程

Posted TheWhc

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了计算机网络 ---- HTTP/1.1HTTP/2HTTP/3演变过程相关的知识,希望对你有一定的参考价值。

HTTP/1.1、HTTP/2、HTTP/3演变过程

1、HTTP/1.1

1.1 对比HTTP/1.0性能上的改进

1.1.1 TCP长连接方式

使用TCP长连接的方式改善了HTTP/1.0短连接造成的性能开销,HTTP可以在一次TCP连接中不断发送请求

1.1.2 支持管道传输

支持**管道(pipeline)**网络传输,只要第一个请求发出去了,不必等其回来,就可以发第二个请求出去,可以减少整体的响应时间 (串行排队)

1.1.3 支持只发送header而不发送body

先用header判断能否成功,再发数据,节约带宽。

1.1.4 host字段处理

在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)

1.2 HTTP/1.1性能瓶颈

  • 请求/响应头部(Header)未经压缩就发送,首部信息越多延迟越大。HTTP/1.1只能压缩Body的部分;

    首部字段Content-Encoding会告知客户端服务器对实体的主体部分选用的内容编码方式。内容编码是指在不丢失实体信息的前提下所进行的压缩。 
    
    常见的4种内容编码的方式:
    - gzip
    - compress
    - deflate
    - identity
    
    但是首部信息不能被压缩。这就带来了HTTP头部巨大的问题,由于HTTP协议是无状态的,每一个请求都得携带HTTP头部,特别是对于有携带cookie的头部,而cookie的大小通常很大
    
  • 发送冗长的首部。每次互相发送相同的首部造成的浪费较多

  • 服务器是按请求的顺序响应的,如果服务器响应慢,会导致客户端一直请求不到数据,即队头阻塞

  • 没有请求优先级控制

  • 请求只能从客户端开始,服务器只能被动响应

  • 不支持服务器推送消息

  • 并发连接有限,谷歌浏览器最大并发连接数是6个,而且每一个连接都要经过TCP和TLS握手耗时,以及TCP慢启动过程给流量带来的影响

1.3 HTTP/1.1 性能优化手段

  • 尽量避免发送HTTP请求

    通过缓存技术来避免发送 HTTP 请求。客户端收到第⼀个请求的响应后,可以将其缓存在本地磁盘,下次请求的时候,如果缓存没过期,就直接读取本地缓存的响应数据。如果缓存过期,客户端发送请求的时候
    带上响应数据的摘要,服务器⽐对后发现资源没有变化,就发出不带包体的 304 响应,告诉客户端缓存的响应仍然
    有效。

  • 减少HTTP请求的次数

    • 将原本由客户端处理的重定向请求,交给代理服务器处理,这样可以减少重定向请求的次数;

    • 将多个小资源合并成⼀个大资源再传输,能够减少 HTTP 请求次数以及 头部的重复传输,再来减少 TCP 连
      接数量,进⽽省去 TCP 握⼿和慢启动的网络消耗;

      将多张小图合并成⼀张大图供浏览器 javascript 来切割使⽤,这样可以将多个请求合并成⼀个请求,但是带来了新的问题,当某张小图片更新了,那么需要重新请求大图片,浪费了⼤量的网络带宽;
      
      将图⽚的⼆进制数据通过 base64 编码后,把编码数据嵌⼊到 html 或 CSS 文件中,以此来减少网络请求次数;
      
      将多个体积较小的 JavaScript ⽂件使⽤ webpack 等⼯具打包成⼀个体积更⼤的 JavaScript ⽂件,以⼀个请求替代了很多个请求,但是带来的问题,当某个 js ⽂件变化了,需要重新请求同⼀个包⾥的所有 js ⽂件;
      
    • 按需访问资源,只访问当前⽤户看得到/用得到的资源,当客户往下滑动,再访问接下来的资源,以此达到延迟请求,也就减少了同⼀时间的 HTTP请求次数

  • 减少服务器的HTTP响应数据大小

    通过压缩响应资源,降低传输资源的大小,从而提高传输效率,所以应当选择更优秀的压缩算法。
    不管怎么优化 HTTP/1.1 协议都是有限的,不然也不会出现 HTTP/2 和 HTTP/3 协议

  • 提升并发连接数量

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

2、HTTP/2

HTTP/2协议是基于HTTPS的,所以HTTP/2的安全性是有保障的

2.1 对比HTTP/1.1性能上的改进

2.1.1 头部压缩

HTTP/2会压缩头(Header)如果你同时发出多个请求,它们的头是一样的或是相似的,那么,协议会帮你消除重复的部分。

这就是所谓的HPACK算法: 在客户端和服务器同时维护一张头信息表,所有字段都会存入这张表,生成一个索引号,以后就不会发送同样字段了,只发送索引号,这样就提高速度了

HPACK算法:
- 静态字典
- 动态字典
- Huffman编码(压缩算法)

对于常见的HTTP头部通过静态表和Huffman编码的方式,将体积压缩了近一半,而且针对后续的请求头部,还可以建立动态表,将体积压缩近90%,大大提高了编码效率,同时节约了带宽资源。

2.1.2 二进制压缩

HTTP/2不像HTTP/1.1里的纯文本形式的报文,而是全面采用了二进制格式,头信息和数据体都是二进制,并且统称为帧(frame):头信息帧和数据帧

计算机收到报文后,无需将明文的报文转化为二进制,而是直接解析二进制报文,增加了数据传输的效率

2.1.3 数据流(Stream)

HTTP/2 的数据包不是按顺序发送的,同⼀个连接里面连续的数据包,可能属于不同的回应。因此,必须要对数据包做标记,指出它属于哪个回应。

每个请求或回应的所有数据包,称为⼀个数据流( Stream )。每个数据流都标记着⼀个独一无二的编号,其中规
定客户端发出的数据流编号为奇数, 服务器发出的数据流编号为偶数
。客户端还可以指定数据流的优先级。优先级高的请求,服务器就先响应该请求。

2.1.4 多路复用

HTTP/2是可以在一个连接中并发多个请求或回应,而不用按照顺序一一对应。

移除了HTTP/1.1中的串行请求,不需要排队等待,也就不会再出现 队头阻塞的问题,降低了延迟了,大幅度提高了连接的利用率

举例来说,在一个 TCP 连接里,服务器收到了客户端 A 和 B 的两个请求,如果发现 A 处理过程非常耗时,于是就回应 A 请求已经处理好的部分,接着回应 B 请求,完成后,再回应 A 请求剩下的部分。 

2.1.5 服务器推送

HTTP/2还在一定程度上改善了传统的请求-应答工作模式,服务器不再是被动响应,也可以主动向客户端发送消息.

举例来说,在浏览器刚请求 HTML 的时候,就提前把可能会用到的 JS、CSS 文件等静态资源主动发给客户端,减少延时的等待,也就是服务器推送(Server Push,也叫 Cache Push)

2.2 HTTP/2性能瓶颈

2.2.1 队头阻塞

  • 多个HTTP请求在复用一个TCP连接,下层的TCP协议是不知道有多少个HTTP请求的。所以一旦发生了丢包现象,就会触发TCP的重传机制,这样在一个TCP连接中的所有的HTTP请求都必须等待这个丢了的包被重传回来
    • HTTP/1.1中的管道(pipeline)传输中如果有一个请求阻塞了,那么队列后请求也统统被阻塞住了
    • HTTP/2多请求复用一个TCP连接,一旦发生丢包,就会阻塞住所有的HTTP请求

原因:

HTTP/2虽然通过Stream的并发能力,解决了HTTP/1队头阻塞的问题,但是HTTP/2还是存在"队头阻塞"问题,只不过问题不是在HTTP这一层面,而是在TCP这一层。HTTP/2多个请求是跑在一个TCP连接中的,那么当TCP丢包时,整个TCP都要等待重传,那么就会阻塞该TCP连接中的所有请求

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

图中发送方发送了很多个 packet,每个 packet 都有⾃⼰的序号,你可以认为是 TCP 的序列号,其中 packet 3 在
网络中丢失了,即使 packet 4-6 被接收方收到后,由于内核中的 TCP 数据不是连续的,于是接收⽅的应用层就无法从内核中读取到,只有等到 packet 3 重传后,接收方的应用层才可以从内核中读取到数据,这就是 HTTP/2 的
队头阻塞问题,是在 TCP层面发⽣的。

2.2.2 TCP与TLS的握手时延迟

发起HTTP请求时,需要经过TCP三次握手和TLS四次握手(TLS1.2)的过程,因此需要3个RTT的时延才能发出请求数据。(TCP三次握手占1个RTT时延,TLS四次握手占2个RTT时延)。

另外,TCP由于具有【拥塞控制】的特性,所以刚建立连接的TCP会有个【慢启动】的过程,它会对TCP连接产生减速效果。

拥塞控制主要有四种方法: 慢开始、拥塞避免、快重传、快恢复

2.2.3 网络迁移需要重新连接

⼀个 TCP 连接是由四元组(源 IP 地址,源端口,⽬标 IP 地址,⽬标端口)确定的,这意味着如果 IP 地址或者端口变动了,就会导致需要 TCP 与 TLS 重新握手,这不利于移动设备切换网络的场景,比如 4G 网络环境切换成
WIFI。

2.3 补充

并发传输

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 中的内容(头部和包体);

nginx 中,可以通过 http2_max_concurrent_streams 配置来设置 Stream 的上限,默认是 128 个。

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

3、HTTP/3

HTTP/1.1、HTTP/2都是基于TCP传输层的问题,所以HTTP/3把HTTP下层的TCP协议改成了UDP

UDP是一个简单的、不可靠的传输协议,而且UDP包之间是无序的,也没有依赖关系。

UDP是不需要连接的,也就不需要握手和挥手的过程,所以天然的就比TCP快。

HTTP/3 不仅仅只是简单的将传输协议替换成了UDP,还基于UDP协议在应用层实现了QUIC协议,它具有类似TCP的连接管理、拥塞窗口、流量控制的网络特性,相当于将不可靠传输的UDP协议变成"可靠"的了。

3.1 QUIC特点

基于UDP的QUIC协议可以实现类似TCP的可靠性传输。

  • QUIC 有自己的一套机制可以保证传输的可靠性的。当某个流发生丢包时,只会阻塞这个流,其他流不会受到影响
  • TLS3 升级成了最新的 1.3 版本,头部压缩算法也升级成了 QPack
  • HTTPS 要建立一个连接,要花费 6 次交互,先是建立三次握手,然后是 TLS/1.3的三次握手。QUIC 直接把以往的 TCP 和 TLS/1.3 的 6 次交互合并成了 3 次,减少了交互次数

QUIC 是⼀个在 UDP 之上的伪 TCP + TLS + HTTP/2的多路复用的协议。

3.1.1 无队头阻塞

QUCI协议也有类似HTTP/2 Stream与多路复用的概念,也是可以在同一条连接上并发传输多个Stream,Stream可以认为就是一条HTTP请求。

由于QUIC使用的传输协议是UDP,UDP不关心数据包的顺序,如果数据包丢失,UDP也不会关心。

不过QUIC协议会保证数据包的可靠性,每个数据包都有一个序号唯一标识。当某个流中的一个数据包丢失了,即使该流的其他数据包到达了,数据也无法被HTTP/3读取,直到QUIC重传丢失的报文,数据才会交给HTTP/3。而其它流的数据报文只要被完整就收了,HTTP/3就可以读取到数据。

这点和HTTP/2不同,HTTP/2只要某个流中的数据报丢失了,其它流也会因此受影响。

所以,QUIC连接上的多个Stream之间并没有依赖,都是独立的,某个流发送丢包了,只会影响该流,其它流不受影响

3.1.2 更快的连接建立

对于HTTP/1和HTTP/2协议,TCP和TLS是分层的,分别属于内核实现的传输层、openssl库实现的表示层,因此它们难以合并在一起,需要分批次来握手,先TCP握手,再TLS握手。

HTTP/3 在传输数据前虽然需要 QUIC 协议握⼿,这个握手过程只需要 1 RTT,握手的目的是为确认双⽅的「连接
ID」,连接迁移就是基于连接 ID 实现的。

但是 HTTP/3 的 QUIC 协议并不是与 TLS 分层,而是QUIC 内部包含了 TLS,它在自己的帧会携带 TLS ⾥的“记
录”,再加上 QUIC 使⽤的是 TLS1.3,因此仅需 1 个 RTT 就可以「同时」完成建立连接与密钥协商,甚⾄在第二次连接的时候,应用数据包可以和 QUIC 握手信息(连接信息 + TLS 信息)⼀起发送,达到 0-RTT 的效果。

3.1.3 连接迁移

基于 TCP 传输协议的 HTTP 协议,由于是通过四元组(源 IP、源端⼝、⽬的 IP、⽬的端⼝)确
定⼀条 TCP 连接,那么当移动设备的⽹络从 4G 切换到 WIFI 时,意味着 IP 地址变化了,那么就必须要断开连
接,然后重新建⽴连接,⽽建⽴连接的过程包含 TCP 三次握⼿和 TLS 四次握⼿的时延,以及 TCP 慢启动的减速
过程,给⽤户的感觉就是网络突然卡顿了⼀下,因此连接的迁移成本是很⾼的。
而QUIC 协议没有⽤四元组的⽅式来“绑定”连接,而是通过连接 ID来标记通信的两个端点,客户端和服务器可以各自选择⼀组 ID 来标记自己,因此即使移动设备的网络变化后,导致 IP 地址变化了,只要仍保有上下⽂信息(比如连接 ID、TLS 密钥等),就可以“⽆缝”地复用原连接,消除重连的成本,没有丝毫卡顿感,达到了连接迁移的功能。

3.2 HTTP/3协议

HTTP/3同HTTP/2一样采用二进制帧的结构,不同的地方在于HTTP/2的二进制帧里需要定义Stream,而HTTP/3自身不需要再定义Stream,直接使用QUIC里的Stream,所以HTTP/3的帧结构也变得简单了。

  • Frame Header

    • HTTP/3帧头只有两个字段:类型和长度

      • 类型大体上分为数据帧和控制帧两大类,HEADER帧(HTTP头部)和DATA帧(HTTP包体)属于数据帧
    • HTTP/3在头部压缩算法升级成了QPACK。与HTTP/2中的HPACK编码方式相似,QPACK也采用了也采用了静态表、动态表和Huffman编码

      静态表的变化:
      	- HTTP/2中的HPACK静态表只有61项,HTTP/3中的QPACK静态表扩大到91项
      Huffman编码变化:
      	- 和HTTP/2对比并没有多大不同
      动态表的变化:
      	- QUIC会有两个特殊的单向流,用来同步双方的动态表。
      
  • Fram Payload

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

4、总结

4.1 HTTP/1.1

  • 特点
    • 支持TCP长连接
    • 支持管道传输
    • 支持只发送header而不发送body
    • host字段处理
  • 缺陷
    • 头部(Header)未经压缩就发送
    • 发送冗长的首部
    • 队头阻塞(HTTP请求响应模型)
    • 没有请求优先级控制
    • 服务器不主动推送
    • 并发连接有限、连接耗时(TCP和TLS握手、TCP慢启动)

4.2 HTTP/2

HTTP/2协议是基于HTTPS的, 支持多个流并发传输的能力,但传输层仍然是TCP协议,还是存在缺陷

  • 特点
    • 头部压缩
    • 二进制压缩
    • 数据流(Stream)
    • 多路复用
    • 服务器推送
  • 缺点
    • 队头阻塞(TCP段丢失)
    • TCP和TLS握手时延,TCP三次握手和TLS四次握手(SSL1.2),共有3-RTT的时延
    • 网络迁移需要重新连接

4.3 HTTP/3

传输层从TCP替换成了UDP,并在UDP协议上开发了QUIC协议,来保证数据的可靠传输

  • 特点
    • 无队头阻塞
    • 建立连接速度快
    • 连接迁移

4.4 脑图

参考:图解网络 — 小林coding

以上是关于计算机网络 ---- HTTP/1.1HTTP/2HTTP/3演变过程的主要内容,如果未能解决你的问题,请参考以下文章

计算机网络HTTP 与 HTTPS ( HTTP 发展过程 | HTTP/1.1 与 HTTP/2 对比 | HTTP 报文格式 )

Http 0.9 Http 1.0 Http 1.1 Http 2.0区别

网络请求

什么是HTTP/2?HTTP/2和HTTP/1.1区别是什么?

HTTP0.9 HTTP1.0 HTTP 1.1 HTTP 2.0区别

NodeJs 中的 http、https 和 http2