6.浏览器中的网络

本篇是这个专栏的第六章:《浏览器中的网络》。本章分为三节。

谈及浏览器中的网络,就避不开 HTTP。我们知道 HTTP 是浏览器中最重要且使用最多的协议,是浏览器和服务器之间的通信语言,也是互联网的基石。而随着浏览器的发展,HTTP 为了能适应新的形式也在持续进化,学习 HTTP 的最佳途径就是了解其发展史,所以在接下来的三节文章中,从浏览器发展的视角来学习 HTTP 演进。这三节分别是即将完成使命的 HTTP/1、正在向我们走来的 HTTP/2,以及未来的 HTTP/3。

29 | HTTP/1:HTTP性能优化

本文主要介绍的是 HTTP/1.1,我们先来学习下 HTTP/1.1 的进化史,然后再介绍在进化过程中所遇到的各种瓶颈,以及对应的解决方法。

超文本传输协议HTTP/0.9

HTTP/0.9 是于 1991 年提出的,主要用于学术交流,需求很简单——用来在网络之间传递HTML 超文本的内容,所以被称为超文本传输协议。 HTTP/0.9 的实现有以下三个特点:

  • 第一个是只有一个请求行,并没有 HTTP 请求头和请求体,因为只需要一个请求行就可以完整表达客户端的需求了。

  • 第二个是服务器也没有返回头信息,这是因为服务器端并不需要告诉客户端太多信息,只需要返回数据就可以了。

  • 第三个是返回的文件内容是以 ASCII 字符流来传输的,因为都是 HTML 格式的文件,所以使用 ASCII 字节码来传输是最合适的。

被浏览器推动的HTTP/1.0

变化是这个世界永恒不变的主旋律,1994 年底出现了拨号上网服务,同年网景又推出一款浏览器,从此万维网就不局限于学术交流了,而是进入了高速的发展阶段。 万维网的高速发展带来了很多新的需求,而 HTTP/0.9 已经不能适用新兴网络的发展,所以这时就需要一个新的协议来支撑新兴网络,这就是 HTTP/1.0 诞生的原因。

新兴网络带来了新的需求:首先在浏览器中展示的不单是 HTML 文件了,还包括了 JavaScript、CSS、图片、音频、视频等不同类型的文件。因此支持多种类型的文件下载是 HTTP/1.0 的一个核心诉求,而且文件格式不仅仅局限于 ASCII 编码,还有很多其他类型编码的文件。

为了让客户端和服务器能更深入地交流,HTTP/1.0 引入了请求头响应头,它们都是以为 Key-Value 形式保存的,在 HTTP 发送请求时,会带上请求头信息,服务器返回数据时,会先返回响应头信息。 HTTP/1.0 的方案是通过请求头和响应头来进行协商,在发起请求时候会通过 HTTP 请求头告诉服务器它期待服务器返回什么类型的文件、采取什么形式的压缩、提供什么语言的文件以及文件的具体编码。

缝缝补补的HTTP/1.1

技术继续发展、需求不断迭代更新,HTTP/1.0也不能满足需求了,HTTP/1.1又在HTTP/1.0上继续更新:

改进持久连接

HTTP/1.1 中增加了持久连接的方法,它的特点是在一个 TCP 连接上可以传输多个 HTTP 请求,只要浏览器或者服务器没有明确断开连接,那么该 TCP 连接会一直保持。 HTTP 的持久连接可以有效减少 TCP 建立连接和断开连接的次数,这样的好处是减少了服务器额外的负担,并提升整体 HTTP 的请求时长。 持久连接在 HTTP/1.1 中是默认开启的,所以你不需要专门为了持久连接去 HTTP 请求头设置信息,如果你不想要采用持久连接,可以在 HTTP 请求头中加上Connection: close。目前浏览器中对于同一个域名,默认允许同时建立 6 个 TCP 持久连接.

不成熟的HTTP管线化

如果 TCP 通道中的某个请求因为某些原因没有及时返回,那么就会阻塞后面的所有请求,这就是著名的队头阻塞的问题。 HTTP/1.1 中试图通过管线化的技术来解决队头阻塞的问题。HTTP/1.1 中的管线化是指将多个 HTTP 请求整批提交给服务器的技术,虽然可以整批发送请求,不过服务器依然需要根据请求顺序来回复浏览器的请求。 FireFox、Chrome 都做过管线化的试验,但是由于各种原因,它们最终都放弃了管线化技术.

提供虚拟主机的支持

在 HTTP/1.0 中,每个域名绑定了一个唯一的 IP 地址,因此一个服务器只能支持一个域名。 但是随着虚拟主机技术的发展,需要实现在一台物理主机上绑定多个虚拟主机,每个虚拟主机都有自己的单独的域名,这些单独的域名都公用同一个 IP 地址。 因此,HTTP/1.1 的请求头中增加了 Host 字段,用来表示当前的域名地址,这样服务器就可以根据不同的 Host 值做不同的处理。

对动态生成的内容提供了完美的支持

在设计 HTTP/1.0 时,需要在响应头中设置完整的数据大小,如Content-Length: 901,这样浏览器就可以根据设置的数据大小来接收数据。 不过随着服务器端的技术发展,很多页面的内容都是动态生成的,因此在传输数据之前并不知道最终的数据大小,这就导致了浏览器不知道何时会接收完所有的文件数据。 HTTP/1.1 通过引入 Chunk transfer 机制来解决这个问题,服务器会将数据分割成若干个任意大小的数据块,每个数据块发送时会附上上个数据块的长度,最后使用一个零长度的块作为发送数据完成的标志。这样就提供了对动态内容的支持。

除此之外,HTTP/1.1 还引入了客户端 Cookie 机制和安全机制。

30 | HTTP/2:如何提升网络速度?

HTTP/1.1为网络效率做了大量的优化,最核心的三种方式为:

  • 增加了持久连接。

  • 浏览器为每个域名最多同时支持6个TCP持久连接。

  • 使用CDN的实现域名分片机制。

HTTP/1.1的主要问题

HTTP/1.1对带宽的利用率却并不理想,这也是 HTTP/1.1 的一个核心问题. 带宽是指每秒最大能发送或者接收的字节数。我们把每秒能发送的最大字节数称为上行带宽,每秒能够接收的最大字节数称为下行带宽。

出现宽带利用率不理想的原因,主要为:

  • 第一个原因,TCP的慢启动。

  • 第二个原因,同时开启了多条TCP连接,那么这些连接会竞争固定的宽带。

  • 第三个原因,HTTP/1.1队头阻塞的问题。

HTTP/2的多路复用

HTTP/2 的解决方案可以总结为:一个域名只使用一个 TCP 长连接和消除队头阻塞问题. 具体实现就是:通过引入二进制分帧层,实现 HTTP 的多路复用技术。

HTTP/2其他特性

  • 可以设置请求的优先级。

  • 服务器推送。

  • 头部压缩。

HTTP/2 协议规范于 2015 年 5 月正式发布,在那之后,该协议已在互联网和万维网上得到了广泛的实现和部署。从目前的情况来看,国内外一些排名靠前的站点基本都实现了 HTTP/2 的部署。使用 HTTP/2 能带来 20%~60% 的效率提升,至于 20% 还是 60% 要看优化的程度。总之,我们也应该与时俱进,放弃 HTTP/1.1 和其性能优化方法,去“拥抱”HTTP/2

31 | HTTP/3.0:甩掉TCP、TLS的包袱,构建高效网络

和通常一样,介绍 HTTP/3 之前,我们先来看看 HTTP/2 到底有什么缺陷。

1.TCP的队头阻塞

在 TCP 传输过程中,由于单个数据包的丢失而造成的阻塞称为 TCP 上的队头阻塞。 有测试数据表明,当系统达到了 2% 的丢包率时,HTTP/1.1 的传输效率反而比 HTTP/2 表现得更好。

2.TCP建立连接的延时

网络延迟又称为 RTT(Round Trip Time)。我们把从浏览器发送一个数据包到服务器,再从服务器返回数据包到浏览器的整个往返时间称为 RTT。RTT 是反映网络性能的一个重要指标。

3.TCP协议僵化

虽然我们知道了TCP的队头阻塞和建立连接延时等缺点,但是通过改进TCP协议来解决这些问题非常困难,这里说的非常困难就是指TCP协议僵化。 TCP协议僵化体现在两个方面:第一个是中间设备的僵化;除中间设备的僵化外,操作系统也是导致TCP协议僵化的另外一个原因。

QUIC协议

HTTP/3 选择了一个折衷的方法——UDP 协议,基于 UDP 实现了类似于 TCP 的多路数据流、传输可靠性等功能,我们把这套功能称为 QUIC 协议。 HTTP/3 中的 QUIC 协议集合了以下几点功能:

  • 实现了类似 TCP 的流量控制、传输可靠性的功能。虽然 UDP 不提供可靠性的传输,但 QUIC 在 UDP 的基础之上增加了一层来保证数据可靠性传输。它提供了数据包重传、拥塞控制以及其他一些 TCP 中存在的特性。

  • 集成了 TLS 加密功能。

  • 实现了 HTTP/2 中的多路复用功能。

  • 实现了快速握手功能。

HTTP/3的挑战

通过上面的分析,我们相信在技术层面,HTTP/3 是个完美的协议。不过要将 HTTP/3 应用到实际环境中依然面临着诸多严峻的挑战,这些挑战主要来自于以下三个方面:

  • 第一,从目前的情况来看,服务器和浏览器端都没有对 HTTP/3 提供比较完整的支持。Chrome 虽然在数年前就开始支持 Google 版本的 QUIC,但是这个版本的 QUIC 和官方的 QUIC 存在着非常大的差异。

  • 第二,部署 HTTP/3 也存在着非常大的问题。因为系统内核对 UDP 的优化远远没有达到 TCP 的优化程度,这也是阻碍 QUIC 的一个重要原因。

  • 第三,中间设备僵化的问题。这些设备对 UDP 的优化程度远远低于 TCP,据统计使用 QUIC 协议时,大约有 3%~7% 的丢包率。