HTTP1.0 1.1 2.0 3.0工作原理探究

387 阅读13分钟

HTTP1.0 1.1 2.0 3.0工作原理探究

1.1 HTTP简介

HTTP协议,即超文本传输协议(Hypertext transfer protlcol)。是一种详细规定了万维网服务器之间通讯的规则,通过因特尔传送万维网文档的数据传送协议。

HTTP协议为TCP/IP模型中的应用层的协议。HTTP协议通常承载TCP协议之上,有时也承载于TLS/SSL协议层之上,即HTTPS。

1.2 HTTP 工作原理

HTTP协议定义了Web客户端如何从Web服务器请求Web页面,以及服务器如何把Web页面传送给客户端。HTTP协议采用了请求/响应模型。客户端向服务器发送一个请求报文,请求报文包含请求的方法,URL,协议版本,请求头和请求数据。服务器以一个状态行为作为响应,响应的内容包括协议的版本、成功或者错误代码,服务器信息,响应头部和响应数据。

HTTP请求响应的步骤:

  1. 客户端连接Web服务器
  2. 发送HTTP请求
  3. 服务器接收请求并返回HTTP响应
  4. 释放TCP连接
  5. 客户端浏览器解析HTML内容

HTTP是建立在TCP协议之上的,所以HTTP协议的瓶颈及其优化技巧都是基于TCP协议本身的特性,例如tcp建立连接的3次握手和断开连接的4次回收以及每次建立连接带来的RTT延迟时间

1.3 HTTP/1.0

在HTTP/1.0中默认使用短连接。

也就是说,客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。当客户端浏览器访问的某个HTML或其他类型的Web页中包含有其他的Web资源(如JavaScript文件、图像文件、CSS文件等),每遇到这样一个Web资源,浏览器就会重新建立一个HTTP会话。

HTTP协议与TCP/IP协议的关系

HTTP的长链接和短连接本质上是TCP长链接和短连接。HTTP属于应用层,在传输层使用TCP协议,在网络层使用IP协议。IP协议主要解决网络路由和寻址问题,TCP协议主要解决如何在IP层之上可靠地传递数据包,是的网络上接收端收到发送端发出的所有包,并且顺序与发送顺序一致。TCP协议是可靠的,面向连接的。

如何理解HTTP协议是无状态的

HTTP协议是无状态的,指的是对事物处理没有记忆能力,服务器不知道客户端是什么状态。也就是说,打开一个服务器上的网页和上次打开这个服务器上的网页之间是没有任何联系的。HTTP是一个无状态的面向连接的协议,无状态不代表HTTP不能保持TCP连接,更不能代表HTTP使用的是UDP协议。

HTTP1.0存在的问题

  1. 无法复用连接

    每次发送请求,都需要进行一次TCP连接,而TCP的连接释放过程又是比较费事的。这种无连接的特性会使得网络的利用率变低

  2. 队头阻塞

    由于HTTP1.0规定下一个请求必须在前一个请求响应到达之前才能发送,假设前一个请求响应一直不到达,那么下一个请求就不发送,后面的请求就阻塞了

1.4 HTTP1.1

HTTP1.1继承了HTTP1.0的简单,克服了HTTP1.0性能上的问题。

长连接

从HTTP/1.1起,默认使用长连接,用以保持连接特性。

使用长连接的HTTP协议,会在响应头加入这行代码:

Connection:keep-alive

在使用长连接的情况下,当一个网页打开完成后,客户端和服务端之间用于传输HTTPTCP连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。Keep-alive不会永久保持连接,它有一个保持时间,可以在不同服务器软件中设定这个值。实现长连接客户端和服务端都支持长连接。

管道化(pipelining)— 尴尬的假并行传输

HTTP1.1支持请求管道化(pipelining)。

基于HTTP1.1的长连接,使得请求管线化成为可能。 管线化使得请求能够“并行”传输。

例如:

假如响应的主体是一个html页面,页面中包含了很多img,这个时候keep-alive就了很大作用。能够“并行”发送多个请求。(注意,这里的“并行”并不是真正意义上的并行传输)

需要注意的是:服务器必须按照客户端请求的先后顺序依次回送相应的结果,以保证客户端能够区分出每次请求的响应内容。

也就是说,HTTP管道化可以让我们把先进先出队列从客户端(请求队列)迁移到服务端(响应队列)。

如果,客户端同时发了两个请求分别获取html和css,假如说服务器的css资源先准备就绪,服务器也会先发送html,再发送css。 换句话来说,只有等到html响应的资源完全传输完毕后,css响应的资源才开始传输,不允许同时存在两个并行的响应。

可见,HTTP1.1还是无法解决队头阻塞(head of line blocking)的问题。同时“管道化”技术存在各种各样的问题,所以很多浏览器要么根本不支持它,要么直接默认关闭,并且开启的条件很苛刻,而且好像实际也没有什么用处。

真并行传输 — 浏览器优化策略

HTTP1.1支持管道化,但是服务器也必须进行逐个响应的送回,这个是很大的一个缺陷。

实际上,现阶段的浏览器厂商采取了另外一种做法,它允许我们打开多个TCP的会话。

也就是说,我们看到的并行,其实是不同的TCP连接上的HTTP请求和相应。这才是真正的并行!

缓存处理 — 强缓存、协商缓存,启发式缓存(新增)

HTTP1.1还加入了缓存处理(强缓存和协商缓存),新的字段如cache-control,支持断点传输,以及增加了Host字段(使得一个服务器能够用来创建多个Web站点)

HTTP 1.x 的缺陷

连接无法复用:连接无法复用会导致每次请求都经历三次握手和慢启动。三次握手在高延迟的场景下影响较明显,慢启动则对大量小文件请求影响较大(没有达到最大窗口请求就被终止)

  • HTTP/1.0 传输数据时,每次都需要重新建立连接,增加延迟。
  • HTTP/1.1 虽然加入 keep-alive 可以复用一部分连接,但域名分片等情况下仍然需要建立多个 connection,耗费资源,给服务器带来性能压力。

队头阻塞:导致带宽无法被充分利用,以及后续健康请求被阻塞。HOLB是指一系列包(package)因为第一个包被阻塞;当页面中需要请求很多资源的时候,HOLB(队头阻塞)会导致在达到最大请求数量时,剩余的资源需要等待其他资源请求完成后才能发起请求。

  • HTTP 1.0:下个请求必须在前一个请求返回后才能发出,request-response对按序发生。显然,如果某个请求长时间没有返回,那么接下来的请求就全部阻塞了。
  • HTTP 1.1:尝试使用 pipeling 来解决,即浏览器可以一次性发出多个请求(同个域名,同一条 TCP 链接)。但pipeling 要求返回是按序的,那么前一个请求如果很耗时(比如处理大图片),那么后面的请求即使服务器已经处理完,仍会等待前面的请求处理完才开始按序返回。所以,pipeling 只部分解决了 HOLB。

1.5 HTTP 2.0

2015 年,HTTP 2.0 发布。HTTP 2.0 是现行 HTTP 协议(HTTP 1.x)的替代,但它不是重写,HTTP方法/状态码/语义都与 HTTP 1.x 一样。

HTTP 2.0 基于SPDY3,专注于性能,最大的一个目标是在用户和网站间只用一个连接(connection)

二进制传输

HTTP 2.0 采用二进制格式传输数据,而非 HTTP 1.x 的文本格式,二进制协议解析起来更高效。

HTTP 1.x 的请求和响应报文,都是由起始行,首部和实体正文(可选)组成,各部分之间以文本换行符分隔。HTTP2.0 将请求和响应数据分割为更小的帧,并且它们采用二进制编码

多路复用(链接共享)— 真并行传输

  • 流(stream):已建立连接上的双向字节流。
  • 消息:与逻辑消息对应的完整的一系列数据帧。
  • 帧(frame):HTTP2.0通信的最小单位,每个帧包含头部,至少也会标识出当前所属的流(stream_id)

所有HTTP2.0通信都在一个TCP链接上完成,这个链接可以承载任意流量的双向数据流。

  • 同个域名只需要占用一个 TCP 连接,使用一个连接并行发送多个请求和响应,消除了因多个 TCP 连接而带来的延时和内存消耗。
  • 并行交错地发送多个请求,请求之间互不影响。
  • 并行交错地发送多个响应,响应之间互不干扰。
  • 这些帧可以乱序发送,然后再根据每个帧头部的流标志符(stream_id)重新封装
  • 在 HTTP/2 中,每个请求都可以带一个 31bit 的优先值,0 表示最高优先级, 数值越大优先级越低。有了这个优先值,客户端和服务器就可以在处理不同的流时采取不同的策略,以最优的方式发送流、消息和帧。

可见,HTTP2.0实现了真正的并行传输,它能够在一个TCP上进行任意数量的HTTP请求。而这个强大的功能基于“二级制分帧”的特性。

头部压缩

HTTP1.X中,头部元数据都是以纯文本的形式发送的,通常会给每个请求增加500-8000字节的负荷。如cookie等。

HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header_files表,既避免重复header的传输,又减少了需要传输的大小。高效的压缩算法可以很大的压缩header,减少发送包的数量从而降低延迟。

服务器推送

服务器除了最初请求的响应外,服务器还可以额外向客户端推送资源,而无需客户端明确的需求。

1.6 HTTP 3.0

HTTP 2.0 解决了很多之前旧版本的问题,但是它还是存在一个巨大的问题,主要是底层支持的TCP协议造成的。

HTTP 2.0 使用了多路复用技术,一般来说同一个域名只需要使用一个TCP连接。当这个连接出现丢包的情况,整个TCP都要开始等待重传,也导致了后面的所有数据都被阻塞了。但对于HTTP 1.x 可以开启多个TCP连接,出现这种情况只会影响其中一个连接,剩余的 TCP 连接还可以正常传输数据。

基于这个原因,Google 就更起炉灶搞了一个基于 UDP 协议的 QUIC 协议,并且使用在了 HTTP/3 上,HTTP/3 之前名为 HTTP-over-QUIC,从这个名字中我们也可以发现,HTTP/3 最大的改造就是使用了 QUIC。

QUIC 虽然基于 UDP,但是在原本的基础上新增了很多功能,接下来我们重点介绍几个 QUIC 新功能。

QUIC 新功能

0-RTT

RTT是Round Trip Time的缩写,通俗地说,就是通信一来一回的时间。

​ TCP建立连接的时间 一去 (SYN) 二回 (SYN+ACK)三去 (ACK),相当于一个半来回,所以是1.5RTT

​ HTTP交易时间,用户在浏览器输入网址URL,直到时间流逝1.5RTT之后,TCP才开始运输HTTP Request,浏览器收到服务器的HTTP Response,所以HTTP通信时间总和 = TCP连接时间 + TSL连接时间+HTTP交易时间 = 1.5 RTT + 1 RTT = 2.5 RTT

​ HTTPS 通常将TLS安全保护的HTTP通信,称之为HTTPS,以区别于没有TLS安全防护的HTTP明文通信。HTTPS通信时间总和=TCP连接时间+TLS连接时间+HTTP交易时间=1.5RTT+1.5RTT+1RTT=4RTT

​ HTTP 2.0 在第一次的时候会需要4RTT的时间,在后续的连接重用第一个TCP连接,所以少1.5RTT,因此需要2.5RTT

​ HTTP 3.0 UDP不需要连接,不会带来附加的RTT时间,QUIC协议集成了TCP可靠传输机制,TLS安全加密,HTTP 2.0流量复用技术,重连TLS连接是一个0 RTT事件。

通常将TLS安全保护的HTTP通信,称之为HTTPS,以区别于没有TLS安全防护的HTTP明文通信

​ 页面的整体加载时间= TLS 1.3连接时间+HTTP交易时间=1RTT+1RTT=2RTT

​ 页面重连的加载时间==HTTP交易时间=1RTT

多路复用

虽然 HTTP/2 支持了多路复用,但是 TCP 协议终究是没有这个功能的。QUIC 原生就实现了这个功能,并且传输的单个数据流可以保证有序交付且不会影响其他的数据流,这样的技术就解决了之前 TCP 存在的问题

​ 同 HTTP2.0 一样,同一条 QUIC 连接上可以创建多个 stream,来发送多个 HTTP 请求,但是,QUIC 是基于 UDP 的,一个连接上的多个 stream 之间没有依赖,如果某个Stream丢了一个包,是不影响后续的Stream,不存在TCP的队头阻塞。虽然那个丢包的Stream需要重传,但不影响其他Steam。

另外 QUIC 在移动端的表现也会比 TCP 好。因为 TCP 是基于 IP 和端口去识别连接的,这种方式在多变的移动端网络环境下是很脆弱的。但是 QUIC 是通过 ID 的方式去识别一个连接,不管你网络环境如何变化,只要 ID 不变,就能迅速重连上。

加密认证的报文

​ TCP 协议头部没有经过任何加密和认证,所以在传输过程中很容易被中间网络设备篡改,注入和窃听。比如修改序列号、滑动窗口。但是 QUIC 的 packet 可以说是武装到了牙齿。除了个别报文比如 PUBLIC_RESET 和 CHLO,所有报文头部都是经过认证的,报文 Body 都是经过加密的。

向前纠错机制

​ QUIC 协议有一个非常独特的特性,称为向前纠错 (Forward Error Correction,FEC),每个数据包除了它本身的内容之外,还包括了部分其他数据包的数据,因此少量的丢包可以通过其他包的冗余数据直接组装而无需重传。

向前纠错牺牲了每个数据包可以发送数据的上限,但是减少了因为丢包导致的数据重传,因为数据重传将会消耗更多的时间(包括确认数据包丢失、请求重传、等待新数据包等步骤的时间消耗)

参考文献

—— 《HTTP长连接、短连接究竟是什么?》

—— 《快速掌握HTTP1.0 1.1 2.0 3.0的特点及其区别》

—— 《一文读懂 HTTP/2 及 HTTP/3 特性》

—— 《HTTP 2.0 协议详解》