vlambda博客
学习文章列表

HTTP协议的演进之路


作者:唐弢 | 编辑:皮皮哥


HTTP协议的演进之路 HTTP的发展历程


整个http协议的发展过程,主要是围绕了两个词:速度和效率。

下图是从FEPlus截的一张图,精确地列举了http0.9到http3的演进过程,及该版本的关键技术:

  • HTTP 0.9

  • HTTP 1.0 基本成型

  • HTTP 1.1 支持连接复用和分块发送

  • HTTP 2 (SPDY作为它的前身)支持多路复用,头部压缩

  • HTTP 3 (QUIC作为它的前身)支持UDP实现的传输优化

HTTP协议的演进之路

我们可以看出,与其说http协议的版本在不断提升,不如说http标准协议其实是在不断吸收其他优秀技术,将其标准化进入http协议,从而实现了自身的版本升级。

由于http协议标准涉及的内容很多,我们就从“速度与效率”出发,重点谈一下传输能力的演进过程。


HTTP协议的演进之路 HTTP 1.1


【TCP连接复用】

我们先来看一下http1.1在传输上最重要的能力,也就是“TCP连接复用”。

我们知道http协议在传输层面上,实际上是使用tcp连接的。在http 1.1之前,每一次http请求,都要在服务端和客户端之间建立1个甚至多个tcp连接。由于tcp连接的建立代价很大,传输窗口也是逐步变大的,所以这样的传输效率会很低。

很显然,对于同一个域名(客户端和服务端ip是固定的),我们可以只建立一个tcp连接,并且长时间不关闭它,让http协议内容都在其上进行传输。

HTTP协议的演进之路

如图,上方场景中,tcp的耗时是比http长一些的(因为握手和挥手的消耗);此时我们会看到,如果使用tcp连接复用,这部分的消耗就会被削减。同时,在下方场景下,长tcp的传输窗口可以被打开到较大,实际的传输速度也会比上图要高得多。


【TCP并行多开】

在连接复用的基础上,我们如果继续采用多个tcp连接并行多开的方案,可以得到更高的效率。HTTP1.1时代,通过并行连接的方式解决,浏览器为每个域名维护了6个TCP连接。当然,高效率带来的代价是更高的消耗。

HTTP协议的演进之路


HTTP协议的演进之路 队头阻塞


那么在http 1.1的模式下, 传输上还有什么问题吗?让我们对上图带入一些实际上的细节:在一次http请求的发送和响应时,有时候对方会“卡住”而并没有传送任何内容,这等于是白白占用着tcp连接。

HTTP协议的演进之路

如图,http1在传输过程中分为两段,中间有一个较长的lag期,并不传送任何数据;最现实的场景可以是,http响应时,先对header进行了响应,但是实际的body可能还没有处理完毕,所以无法快速返回。很显然,这个缓慢的http1不仅影响了自己的传输,也会影响同一个tcp连接中的后续http传输。


这里我们就要聊到本文中最重要的一个概念:队头阻塞(Head of line blocking,或HOL blocking)。你可以理解它为:当单个(慢)对象阻止其他/后续的对象前进时,从而产生的阻塞现象。


HTTP协议的演进之路 HTTP 2.0


【tcp多路复用】

因为http1.1在http层的队头阻塞问题,所以http1.1使用了TCP“并行多开”的方案来减弱它的影响。但如果我们需要为每个域名都维护6个tcp长连接,很多时候在性能上这是无法接受的。接下来让我们来看一下http2.0的解决方案。

HTTP协议的演进之路

如图,在一个tcp连接中,http2.0使用stream的概念进行传输。它可以让一次http响应可以被拆分成多个stream;同时,多个stream在传输时可以打乱顺序。这样,stream1的数据可以分为两段来传输,当第二段“卡住”时,其他Stream可以“插队”传输。这种解决方案,就是tcp多路复用。

这样,http2可以不依赖tcp连接多开来解决问题,从而提升了tcp连接的利用率。


【其他优化】

  • 头部压缩,通过HPACK编码减少传输带宽

  • 服务端推送,减少客户端发起请求的次数


【仍旧存在的问题】

前面我们可以看到,http层的队头阻塞之所以会出现,是因为http1.1中,http的传输是有序的,并且每个http包是不可中断的。http 2.0解决了http层的队头阻塞问题,但是tcp层依旧存在类似的队头阻塞问题。

例如,一个tcp包出现丢包或者高延迟时,还是会影响当前tcp连接上的传输的。这是tcp本身的特性(滑动窗口、累计确认)导致的。除非修改tcp协议本身,否则队头阻塞这个问题没有办法从根本上解决。

所以我们的思路就转向到了另一个传输协议:udp。


HTTP协议的演进之路 QUIC的多路复用


http3.0协议使用QUIC,解决了这个问题。QUIC的全称是,Quick UDP Internet Connections,意思其实是基于UDP的互联网连接协议。

QUIC也是使用Stream传输的,但是Stream之间不会有绝对的传输顺序,同时每个stream也可以分段传输。这样QUIC可以在每一条Stream上做拥塞控制,数据包重传。

HTTP协议的演进之路

如上图,黄色,深绿和浅绿是三个不同的stream,他们在QUIC协议下,既可以分拆,也可以乱序传输;这样,之前的tcp层队头阻塞问题就被解决了。


同时,由于QUIC是使用udp协议的,此时应该如何保证数据可靠交付?答案就是在每个QUIC包中,使用offset,递增序列号,以及CRC校验。

HTTP协议的演进之路


HTTP协议的演进之路 HTTP 3.0


【HTTP 3.0的发展历程】

HTTP协议的演进之路

那么接下来我们来看一看HTTP3.0(基于QUIC)的一些优秀特性。


【0RTT/1RTT】

首次建立连接只需要1RTT,建立连接之后服务端SCFG文件不过期,之后的建连只需要0RTT。

RTT(Round trip time),指的是发送方发出数据后,接收方收到,并且返回确认,发送方确认该数据被收到,整个过程的时间消耗。

由于采用了UDP协议传输,所以在网络状况很好的情况下,后续的数据传输实际上是0RTT的,因为接收方并不需要像TCP那样返回ACK。

HTTP协议的演进之路


【DH算法进行秘钥协商】

QUIC并不使用https,但是实际上它的加密通信能力可能是更高的。下面是HTTPS的RSA与QUIC的DH算法的比较。


HTTPS采用RSA算法密钥协商

HTTP协议的演进之路


QUIC使用DH算法进行密钥协商

HTTP协议的演进之路

RSA是前向不安全的, DH是前向安全的

什么是前向安全,如果服务端的私钥一旦泄露,那么之前所有的加密数据也不会被泄露。


【用户态协议栈】

QUIC基于UDP实现了HTTP2.0的优秀特性。QUIC将原来TCP在OS内核空间中的实现移到了用户空间(例如拥塞避免、流量控制、丢包重传等),使QUIC使用起来更加灵活、开发迭代速度更快。


【连接迁移】

而 QUIC 协议是基于 UDP 的,天生无面向连接之说,但是我们还是需要维持客户端与服务的逻辑连接的。QUIC中在数据包的头部加了 ConnectionID(64 位的随机数),这样每个 UDP 包里都有同一个连接的 ID,即使手机从 4G 切为 WIFI 了,手机在发送包时,仍然正常发送,而服务器可以根据 ConnectionID 进行组装即可,这也就是无缝连接迁移。


HTTP协议的演进之路 QUIC存在的问题


1 内核处理UDP很慢

TCP应用更广泛,内核层面有很多优化,UDP相关的优化较少


2 对CPU的要求更高

加解密、拥塞控制、可靠传输等逻辑都是在应用层实现,比较耗费CPU资源。而TCP和TLS长期以来的成熟发展、改进,得到了很多硬件的协助。


3 网络设备对UDP的限制

很多企业、运营商和组织对53端口(DNS)以外的UDP流量进行拦截或者限流(因为这些流量近来常被滥用于攻击),所以QUIC协议有可能被某些运营商或防火墙所拦截。