HTTP1、HTTP1.1、http2、http3的区别
1. 改进持久连接
HTTP/1.0每进行一次HTTP通信,都需要经历建立TCP连接、传输HTTP数据和断开TCP连接三个阶段(如下图)。
在当时,由于通信的文件比较小,而且每个页面的引用也不多,所以这种传输形式没什么大问题。但是随着浏览器普及,单个页面中的图片文件越来越多,有时候一个页面可能包含了几百个外部引用的资源文件,如果在下载每个文件的时候,都需要经历建立TCP连接、传输数据和断开连接这样的步骤,无疑会增加大量无谓的开销。 为了解决这个问题,HTTP/1.1中增加了持久连接的方法,它的特点是在一个TCP连接上可以传输多个HTTP 请求,只要浏览器或者服务器没有明确断开连接,那么该TCP连接会一直保持。
从上图可以看出,HTTP的持久连接可以有效减少TCP建立连接和断开连接的次数,这样的好处是减少了服务器额外的负担,并提升整体HTTP的请求时间。
持久连接在HTTP/1.1中是默认开启的,所以你不需要专门为了持久连接去HTTP请求头设置信息,如果你不想要采用持久连接,可以在HTTP请求头中加上**Connection: close(默认为Connection:keep-alive)****。**目前浏览器中对于同一个域名,默认允许同时建立6个TCP持久连接
。
2. 不成熟的HTTP管线化
持久连接虽然能减少TCP的建立和断开次数,但是它需要等待前面的请求返回之后,才能进行下一次请求。如果TCP通道中的某个请求因为某些原因没有及时返回,那么就会阻塞后面的所有请求,这就是著名的队头阻塞的问题。
HTTP/1.1中试图通过管线化的技术来解决队头阻塞的问题。HTTP/1.1中的管线化是指将多个HTTP请求整批提交给服务器的技术,虽然可以整批发送请求,不过服务器依然需要根据请求顺序来回复浏览器的请求。FireFox、Chrome都做过管线化的试验,但是由于各种原因,它们最终都放弃了管线化技术。
3. 提供虚拟主机的支持
在HTTP/1.0中,每个域名绑定了一个唯一的IP地址,因此一个服务器只能支持一个域名。但是随着虚拟主机技术的发展,需要实现在一台物理主机上绑定多个虚拟主机,每个虚拟主机都有自己的单独的域名,这些单独的域名都公用同一个IP地址。 因此,HTTP/1.1的请求头中增加了Host字段,用来表示当前的域名地址,这样服务器就可以根据不同的Host值做不同的处理。
4. 对动态生成的内容提供了完美支持
在设计HTTP/1.0时,需要在响应头中设置完整的数据大小,如Content-Length: 901,这样浏览器就可 以根据设置的数据大小来接收数据。不过随着服务器端的技术发展,很多⻚面的内容都是动态生成的,因此在传输数据之前并不知道最终的数据大小,这就导致了浏览器不知道何时会接收完所有的文件数据。
HTTP/1.1通过引入Chunk transfer机制来解决这个问题,服务器会将数据分割成若干个任意大小的数据块,每个数据块发送时会附上上个数据块的⻓度,最后使用一个零⻓度的块作为发送数据完成的标志。这样 就提供了对动态内容的支持。
5. 客戶端Cookie、安全机制
小结一下
- HTTP是浏览器和服务器的通信语言
- 诞生之初的HTTP/0.9因为需求简单,所以和服务器之间的通信过程也相对简单。
- HTTP/1.0引入了请求头和响应头,主要是为了支持多种类型的文件下载;其次,还提供了Cache机制、用户代理、状态码等基础信息。
- 随着技术和需求的发展,人们对文件传输的速度要求越来越高,故又基于HTTP/1.0推出了HTTP/1.1,增 加了持久连接方法来提升连接效率,同时还尝试使用管线化技术提升效率(不过由于各种原因,管线化技术 最终被各大厂商放弃了)。除此之外,HTTP/1.1还引入了Cookie、虚拟主机的支持、对动态内容的支持等特性。
HTTP1.1和HTTP2的区别
HTTP1的改进和缺点
改进和优化
我们知道HTTP/1.1为网络效率做了大量的优化,最核心的有如下三种方式:
-
1\. 增加了持久连接;
-
2\. 浏览器为每个域名最多同时维护6个TCP持久连接;
-
3\. 使用CDN的实现域名分片机制。
-
复制代码
通过这些方式就大大提高了页面的下载速度,你可以通过下图来直观感受下:
在该图中,引入了CDN,并同时为每个域名维护6个连接,这样就大大减轻了整个资源的下载时间。这里我们可以简单计算下:如果使用单个TCP的持久连接,下载100个资源所花费的时间为100 * n * RTT;若通过上面的技术,就可以把整个时间缩短为100 * n * RTT/(6 * CDN个数)。从这个计算结果来看,我们的页面加载速度变快了不少。
存在的问题
虽然HTTP/1.1采取了很多优化资源加载速度的策略,也取得了一定的效果,但是HTTP/1.1对带宽的利用率却并不理想,这也是HTTP/1.1的一个核心问题。
带宽是指每秒最大能发送或者接收的字节数。我们把每秒能发送的最大字节数称为上行带宽,每秒能够接收的最大字节数称为下行带宽。
之所以说HTTP/1.1对带宽的利用率不理想,是因为HTTP/1.1很难将带宽用满。比如我们常说的100M带宽, 实际的下载速度能达到12.5M/S,而采用HTTP/1.1时,也许在加载⻚面资源时最大只能使用到2.5M/S,很难 将12.5M全部用满。
- 第一个原因,TCP的慢启动。
一旦一个TCP连接建立之后,就进入了发送数据状态,刚开始TCP协议会采用一个非常慢的速度去发送数据,然后慢慢加快发送数据的速度,直到发送数据的速度达到一个理想状态,我们把这个过程称为慢启动
。
你可以把每个TCP发送数据的过程看成是一辆车的启动过程,当刚进入公路时,会有从0到一个稳定速度的 提速过程,TCP的慢启动就类似于该过程。
慢启动是TCP为了减少网络拥塞的一种策略,我们是没有办法改变的。
而之所以说慢启动会带来性能问题,是因为页面中常用的一些关键资源文件本来就不大,如HTML文件、 CSS文件和JavaScript文件,通常这些文件在TCP连接建立好之后就要发起请求的,但这个过程是慢启动,所以耗费的时间比正常的时间要多很多,这样就推迟了宝贵的首次渲染页面的时间了。
- 第二个原因,同时开启了多条TCP连接,那么这些连接会竞争固定的带宽。
你可以想象一下,系统同时建立了多条TCP连接,当带宽充足时,每条连接发送或者接收速度会慢慢向上增 加;而一旦带宽不足时,这些TCP连接又会减慢发送或者接收的速度。比如一个页面有200个文件,使用了3 个CDN,那么加载该网页的时候就需要建立6 * 3,也就是18个TCP连接来下载资源;在下载过程中,当发现带宽不足的时候,各个TCP连接就需要动态减慢接收数据的速度。这样就会出现一个问题,因为有的TCP连接下载的是一些关键资源,如CSS文件、JavaScript文件等,而有的TCP连接下载的是图片、视频等普通的资源文件,但是多条TCP连接之间又不能协商让哪些关键资源优先下载,这样就有可能影响那些关键资源的下载速度了。
- 第三个原因,HTTP/1.1队头阻塞的问题。
我们知道在HTTP/1.1中使用持久连接时,虽然能公用一个TCP管道,但是在一个管道中同 一时刻只能处理一个请求,在当前的请求没有结束之前,其他的请求只能处于阻塞状态。这意味着我们不能 随意在一个管道中发送请求和接收内容。
这是一个很严重的问题,因为阻塞请求的因素有很多,并且都是一些不确定性的因素,假如有的请求被阻塞 了5秒,那么后续排队的请求都要延迟等待5秒,在这个等待的过程中,带宽、CPU都被白白浪费了。
在浏览器处理生成页面的过程中,是非常希望能提前接收到数据的,这样就可以对这些数据做预处理操作,比如提前接收到了图片,那么就可以提前进行编解码操作,等到需要使用该图片的时候,就可以直接给出处理后的数据了,这样能让用戶感受到整体速度的提升。但队头阻塞使得这些数据不能并行请求,所以队头阻塞是很不利于浏览器优化的。
HTTP/1.1所存在的一些主要问题: 慢启动和TCP连接之间相互竞争带宽是由于TCP本身的机制导致的,而队头阻塞是由于HTTP/1.1的机制导致的。
HTTP2改进(多路复用)
虽然TCP有问题,但是我们依然没有换掉TCP的能力,所以我们就要想办法去规避TCP的慢启动和TCP连接之间的竞争问题。
基于此,HTTP/2的思路就是一个域名只使用一个TCP⻓连接来传输数据,这样整个页面资源的下载过程只 需要一次慢启动,同时也避免了多个TCP连接竞争带宽所带来的问题。 另外,就是队头阻塞的问题,等待请求完成后才能去请求下一个资源,这种方式无疑是最慢的,所以 HTTP/2需要实现资源的并行请求,也就是任何时候都可以将请求发送给服务器,而并不需要等待其他请求的完成,然后服务器也可以随时返回处理好的请求资源给浏览器。
所以,HTTP/2的解决方案可以总结为:一个域名只使用一个TCP连接和消除队头阻塞问题**。**可以参考下图:
该图就是HTTP/2最核心、最重要且最具颠覆性的多路复用机制。从图中你会发现每个请求都有一个对应的 ID,如stream1表示index.html的请求,stream2表示foo.css的请求。这样在浏览器端,就可以随时将请求发送给服务器了。
服务器端接收到这些请求后,会根据自己的喜好来决定优先返回哪些内容,比如服务器可能早就缓存好了 index.html和bar.js的响应头信息,那么当接收到请求的时候就可以立即把index.html和bar.js的响应头信息返回给浏览器,然后再将index.html和bar.js的响应体数据返回给浏览器。之所以可以随意发送,是因为每份数据都有对应的ID,浏览器接收到之后,会筛选出相同ID的内容,将其拼接为完整的HTTP响应数据。
HTTP/2使用了多路复用技术,可以将请求分成一帧一帧的数据去传输,这样带来了一个额外的好处,就是 当收到一个优先级高的请求时,比如接收到JavaScript或者CSS关键资源的请求,服务器可以暂停之前的请 求来优先处理关键资源的请求。
多路复用的实现
现在我们知道为了解决HTTP/1.1存在的问题,HTTP/2采用了多路复用机制,那HTTP/2是怎么实现多路复用的呢?你可以先看下面这张图:
从图中可以看出,HTTP/2添加了一个二进制分帧层,那我们就结合图来分析下HTTP/2的请求和接收过程。
- 首先,浏览器准备好请求数据,包括了请求行、请求头等信息,如果是POST方法,那么还要有请求体。
- 这些数据经过二进制分帧层处理之后,会被转换为一个个带有请求ID编号的帧,通过协议栈将这些帧发送 给服务器。
- 服务器接收到所有帧之后,会将所有相同ID的帧合并为一条完整的请求信息。
- 然后服务器处理该条请求,并将处理的响应行、响应头和响应体分别发送至二进制分帧层。
- 同样,二进制分帧层会将这些响应数据转换为一个个带有请求ID编号的帧,经过协议栈发送给浏览器。
- 浏览器接收到响应帧之后,会根据ID编号将帧的数据提交给对应的请求。
从上面的流程可以看出,通过引入二进制分帧层,就实现了HTTP的多路复用技术。
HTTP是浏览器和服务器通信的语言,在这里虽然HTTP/2引入了二进制分帧层,不 过HTTP/2的语义和HTTP/1.1依然是一样的,也就是说它们通信的语言并没有改变,比如开发者依然可以通 过Accept请求头告诉服务器希望接收到什么类型的文件,依然可以使用Cookie来保持登录状态,依然可以使用Cache来缓存本地文件,这些都没有变,发生改变的只是传输方式。这一点对开发者来说尤为重要,这意味着我们不需要为HTTP/2去重建生态,并且HTTP/2推广起来会也相对更轻松了。
HTTP/2其他特性
通过上面的分析,我们知道了多路复用是HTTP/2的最核心功能,它能实现资源的并行传输。多路复用技术是建立在二进制分帧层的基础之上。其实基于二进制分帧层,HTTP/2还附带实现了很多其他功能,下面我 们就来简要了解下。
- 可以设置请求的优先级我们知道浏览器中有些数据是非常重要的,但是在发送请求时,重要的请求可能会晚于那些不怎么重要的请 求,如果服务器按照请求的顺序来回复数据,那么这个重要的数据就有可能推迟很久才能送达浏览器,这对 于用戶体验来说是非常不友好的。 为了解决这个问题,HTTP/2提供了请求优先级,可以在发送请求时,标上该请求的优先级,这样服务器接 收到请求之后,会优先处理优先级高的请求。
- 服务器推送 除了设置请求的优先级外,HTTP/2还可以直接将数据提前推送到浏览器。你可以想象这样一个场景,当用 戶请求一个HTML⻚面之后,服务器知道该HTML⻚面会引用几个重要的JavaScript文件和CSS文件,那么在 接收到HTML请求之后,附带将要使用的CSS文件和JavaScript文件一并发送给浏览器,这样当浏览器解析 完HTML文件之后,就能直接拿到需要的CSS文件和JavaScript文件,这对首次打开⻚面的速度起到了至关 重要的作用。
- 头部压缩 无论是HTTP/1.1还是HTTP/2,它们都有请求头和响应头,这是浏览器和服务器的通信语言。HTTP/2对请求 头和响应头进行了压缩,你可能觉得一个HTTP的头文件没有多大,压不压缩可能关系不大,但你这样想一 下,在浏览器发送请求的时候,基本上都是发送HTTP请求头,很少有请求体的发送,通常情况下⻚面也有 100个左右的资源,如果将这100个请求头的数据压缩为原来的20%,那么传输效率肯定能得到大幅提升。
小结一下
我们首先分析了影响HTTP/1.1效率的三个主要因素: TCP的慢启动
、多条TCP连接竞争带宽
和队头阻塞
。
接下来我们分析了HTTP/2是如何采用多路复用机制来解决这些问题的。多路复用是通过在协议栈中添加二进制分帧层来实现的,有了二进制分帧层还能够实现请求的优先级、服务器推送、头部压缩等特性,从而大大提升了文件传输效率。
HTTP/2协议规范于2015年5月正式发布,在那之后,该协议已在互联网和万维网上得到了广泛的实现和部署。从目前的情况来看,国内外一些排名靠前的站点基本都实现了HTTP/2的部署。使用HTTP/2能带来20%〜60%的效率提升,至于20%还是60%要看优化的程度。总之,我们也应该与时俱进,放弃HTTP/1.1和其性能优化方法,去“拥抱”HTTP/2。
思考:虽然HTTP/2解决了HTTP/1.1中的队头阻塞问题,但是HTTP/2依然是基于TCP协议的,而TCP协议依然存在数据包级别的队头阻塞问题,那么你觉得TCP的队头阻塞是如何影响到HTTP/2性能的呢?
HTTP2依旧存在的缺陷
TCP的队头阻塞
虽然HTTP/2解决了应用层面的队头阻塞问题,不过和HTTP/1.1一样,HTTP/2依然是基于TCP协议的,而 TCP最初就是为了单连接而设计的。你可以把TCP连接看成是两台计算机之前的一个虚拟管道,计算机的一 端将要传输的数据按照顺序放入管道,最终数据会以相同的顺序出现在管道的另外一头。 接下来我们就来分析下HTTP/1.1协议栈中TCP是如何传输数据的。为直观理解,你可以参考下图:
通过上图你会发现,从一端发送给另外一端的数据会被拆分为一个个按照顺序排列的数据包,这些数据包通 过网络传输到了接收端,接收端再按照顺序将这些数据包组合成原始数据,这样就完成了数据传输。
不过,如果在数据传输的过程中,有一个数据因为网络故障或者其他原因而丢包了,那么整个TCP的连接就 会处于暂停状态,需要等待丢失的数据包被重新传输过来。你可以把TCP连接看成是一个按照顺序传输数据的管道,管道中的任意一个数据丢失了,那之后的数据都需要等待该数据的重新传输。为了直观理解,你可以参考下图:
我们就把在TCP传输过程中,由于单个数据包的丢失而造成的阻塞称为TCP上的队头阻塞。 那队头阻塞是怎么影响HTTP/2传输的呢?首先我们来看正常情况下HTTP/2是怎么传输多路请求的,为了直观理解,你可以参考下图:
通过该图,我们知道在HTTP/2中,多个请求是跑在一个TCP管道中的,如果其中任意一路数据流中出现了丢包的情况,那么就会阻塞该TCP连接中的所有请求。这不同于HTTP/1.1,使用HTTP/1.1时,浏览器为每个域名开启了6个TCP连接,如果其中的1个TCP连接发生了队头阻塞,那么其他的5个连接依然可以继续传 输数据。
所以随着丢包率的增加,HTTP/2的传输效率也会越来越差。有测试数据表明,当系统达到了2%的丢包率 时,HTTP/1.1的传输效率反而比HTTP/2表现得更好。
TCP建立连接的延时
除了TCP队头阻塞之外,TCP的握手过程也是影响传输效率的一个重要因素。为了搞清楚TCP协议建立连接的延迟问题,我们还是先来回顾下网络延迟的概念,这会有助于你对后面内容的理解。网络延迟又称为RTT(Round Trip Time)。我们把从浏览器发送一个数据包到服务器,再从服务器返回数据包到浏览器的整个往返时间称为RTT(如下图)。RTT是反映网络性能的一个重要指标。
那建立TCP连接时,需要花费多少个RTT呢?下面我们来计算下。 我们知道HTTP/1和HTTP/2都是使用TCP协议来传输的,而如果使用HTTPS的话,还需要使用TLS协议进行 安全传输,而使用TLS也需要一个握手过程,这样就需要有两个握手延迟过程。
- 在建立TCP连接的时候,需要和服务器进行三次握手来确认连接成功,也就是说需要在消耗完1.5个RTT 之后才能进行数据传输。
- 进行TLS连接,TLS有两个版本TLS1.2和TLS1.3,每个版本建立连接所花的时间不同,大致是需要1〜2个RTT,关于HTTPS我们到后面到安全模块再做详细介绍。
总之,在传输数据之前,我们需要花掉3〜4个RTT。如果浏览器和服务器的物理距离较近,那么1个RTT的 时间可能在10毫秒以内,也就是说总共要消耗掉30〜40毫秒。这个时间也许用戶还可以接受,但如果服务器相隔较远,那么1个RTT就可能需要100毫秒以上了,这种情况下整个握手过程需要300〜400毫秒,这时 用戶就能明显地感受到“慢”了。
TCP协议僵化
现在我们知道了TCP协议存在队头阻塞和建立连接延迟等缺点,那我们是不是可以通过改进TCP协议来解决 这些问题呢?
答案是:非常困难。之所以这样,主要有两个原因。
第一个是中间设备的僵化。要搞清楚什么是中间设备僵化,我们先要弄明白什么是中间设备。我们知道互联 网是由多个网络互联的网状结构,为了能够保障互联网的正常工作,我们需要在互联网的各处搭建各种设 备,这些设备就被称为中间设备。
这些中间设备有很多种类型,并且每种设备都有自己的目的,这些设备包括了路由器、防火墙、NAT、交换 机等。它们通常依赖一些很少升级的软件,这些软件使用了大量的TCP特性,这些功能被设置之后就很少更新了。
所以,如果我们在客戶端升级了TCP协议,但是当新协议的数据包经过这些中间设备时,它们可能不理解包 的内容,于是这些数据就会被丢弃掉。这就是中间设备僵化,它是阻碍TCP更新的一大障碍。
除了中间设备僵化外,操作系统也是导致TCP协议僵化的另外一个原因。因为TCP协议都是通过操作系统内核来实现的,应用程序只能使用不能修改。通常操作系统的更新都滞后于软件的更新,因此要想自由地更新内核中的TCP协议也是非常困难的。
了解HTTP3:甩掉TCP、TLS的包袱,构建高效网络
QUIC协议(全称Quick UDP Internet Connections,快速UDP互联网连接)
HTTP/2存在一些比较严重的与TCP协议相关的缺陷,但由于TCP协议僵化,我们几乎不可能通过修改TCP协 议自身来解决这些问题,那么解决问题的思路是绕过TCP协议,发明一个TCP和UDP之外的新的传输协议。
但是这也面临着和修改TCP一样的挑战,因为中间设备的僵化,这些设备只认TCP和UDP,如果采用了新的 协议,新协议在这些设备同样不被很好地支持。
因此,HTTP/3选择了一个折衷的方法——UDP协议,基于UDP实现了类似于 TCP的多路数据流、传输可靠性等功能,我们把这套功能称为QUIC协议。关于HTTP/2和HTTP/3协议栈的比较,你可以参考下图:
通过上图我们可以看出,HTTP/3中的QUIC协议集合了以下几点功能。
- 实现了类似TCP的流量控制、传输可靠性的功能。虽然UDP不提供可靠性的传输,但QUIC在UDP的基础 之上增加了一层来保证数据可靠性传输。它提供了数据包重传、拥塞控制以及其他一些TCP中存在的特性。
- 集成了TLS加密功能。目前QUIC使用的是TLS1.3,相较于早期版本,TLS1.3有更多的优点,其中最重要的 一点是减少了握手所花费的RTT个数。
- 实现了HTTP/2中的多路复用功能。和TCP不同,QUIC实现了在同一物理连接上可以有多个独立的逻辑数 据流(如下图)。实现了数据流的单独传输,就解决了TCP中队头阻塞的问题。
- 实现了快速握手功能。由于QUIC是基于UDP的,所以QUIC可以实现使用0-RTT或者1-RTT来建立连接, 这意味着QUIC可以用最快的速度来发送和接收数据,这样可以大大提升首次打开⻚面的速度。
HTTP/3的挑战
通过上面的分析,我们相信在技术层面,HTTP/3是个完美的协议。不过要将HTTP/3应用到实际环境中依然 面临着诸多严峻的挑战,这些挑战主要来自于以下三个方面。
第一,从目前的情况来看,服务器和浏览器端都没有对HTTP/3提供比较完整的支持。Chrome虽然在数年前 就开始支持Google版本的QUIC,但是这个版本的QUIC和官方的QUIC存在着非常大的差异。
第二,部署HTTP/3也存在着非常大的问题。因为系统内核对UDP的优化远远没有达到TCP的优化程度,这 也是阻碍QUIC的一个重要原因。
第三,中间设备僵化的问题。这些设备对UDP的优化程度远远低于TCP,据统计使用QUIC协议时,大约有 3%〜7%的丢包率。
小结一下
我们首先分析了HTTP/2中所存在的一些问题,主要包括了TCP的队头阻塞、建立TCP连接的延时、TCP协议 僵化等问题。
这些问题都是TCP的内部问题,因此要解决这些问题就要优化TCP或者“另起炉灶”创造新的协议。由于优 化TCP协议存在着诸多挑战,所以官方选择了创建新的QUIC协议。
HTTP/3正是基于QUIC协议的,你可以把QUIC看成是集成了“TCP+HTTP/2的多路复用+TLS等功能”的一 套协议。这是集众家所长的一个协议,从协议最底层对Web的文件传输做了比较彻底的优化,所以等生态相对成熟时,可以用来打造比现在的HTTP/2还更加高效的网络。
虽说这套协议解决了HTTP/2中因TCP而带来的问题,不过由于是改动了底层协议,所以推广起来还会面临 着巨大的挑战。