HTTP/2 in Action 中文版
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

2.1 HTTP/1.1和当前的万维网

在第1章,我们了解到HTTP是一种请求-响应协议,最初设计用于请求单个纯文本内容,在请求完成后会终止连接。HTTP/1.0引入了其他媒体类型,例如支持图像。HTTP/1.1确保在默认情况下开启持久连接(假设网页需要更多请求)。

这些是很好的改进,但是自上次修订HTTP(1997年的HTTP/1.1版。尽管正式规范已经修订了几次,如第1章所述,在撰写本书时还在进行修订)以来互联网发生了很大变化。如图2.1所示,通过HTTP Archive趋势网站(https://httparchive.org/reports/state-of-the-web),可以看到过去8年中网站的增长情况。忽略2017年5月左右的轻微下跌,那时HTTP Archive的测算出了点问题[1]

图2.1 网站加载内容平均大小(2014年—2018年[2]

可以看到,普通网站请求80~90个资源,下载近1.8 MB的数据(通过网络传输的数据量,包括使用gzip或类似应用程序压缩的文本资源)。未压缩的网站现在超过3MB,这导致移动设备等低性能设备的其他问题。

计算这个平均值的样本差异很大。例如,查看美国的Alexa排名前10的网站[3],会看到表2.1中显示的结果。

表2.1 美国访问量排名前10网站

该表显示,某些网站(如Wikipedia和Google)经过大幅优化后,需要加载的资源很少,但其他网站则需要加载数百个资源、数MB的数据。因此,查看网站的这些平均统计数据的价值之前一直受到质疑[4]。但无论如何,很明显,资源增多、数据量增大是一个趋势。网站的增长主要是因为媒体越来越丰富,例如,图像和视频在大多数网站上都很常见。此外,网站变得越来越复杂,需要多个框架和依赖项才能正确显示其内容。

网页最初都是静态的页面,但随着Web的动态性变好,网页开始在服务端动态生成,例如使用CGI(Common Gateway Interface,公共网关接口)或Java Servlet/Java Server Page(JSP)动态生成。随后,从服务端生成完整页面变成只生成基本HTML页面,其他由客户端JavaScript进行AJAX(Asynchronous JavaScript and XML)调用。这些AJAX调用向Web服务器发出额外请求,以更改网页内容,而无须重新加载整页或要求在服务端动态生成基本映像。你可以看看网络搜索的变化。在网络发展的早期,在搜索引擎出现之前,网站和网页目录是在网络上查找信息的主要方式,它们是静态的,偶尔才更新。然后第一个搜索引擎出现了,其允许用户提交搜索表单并从服务器返回结果(服务端生成的动态页面)。如今,大多数搜索网站会在你发出“搜索”命令之前在下拉菜单中提出建议。Google更进一步,在用户输入时即显示结果(但它在2017年夏天撤销了这一功能,因为越来越多的搜索转移到移动设备,这种功能变得没那么必要了)。

除了搜索引擎之外,各种网页也大量使用AJAX请求,从加载新帖子的社交媒体网站到随时更新的新闻网站。所有这些额外的媒体和AJAX请求使得网站化身为更有趣的网络应用。然而,HTTP协议在设计之初并未考虑到资源的这种巨量增长,协议的简单性设计不可避免地遇到了一些根本上的性能问题。

2.1.1 HTTP/1.1根本的性能问题

例如一个有一些文本和两个图像的简单网页。假设一个请求需要50 ms才能通过互联网传输到Web服务器,并且该网站是静态的(因此Web服务器从文件服务器中提取文件并将其发回,比如说,在10 ms内)。同样,Web浏览器需要10 ms来处理图像并发送下一个请求。这些数字是假设的。如果你有一个动态创建页面的内容管理系统(CMS)(例如WordPress,其基于PHP来处理页面),10 ms的服务器时间可能不准确,具体取决于服务器上正在进行的运算和数据库操作。此外,与HTML页面相比,图像可能很大并且发送时间更长。在本章的后面我们会看到一些真实的例子,但是对于这个简单的例子,HTTP的流程如图2.2所示。

图2.2 在一个简单的网站示例中,HTTP请求及响应的流程

方框表示客户端或服务端的处理,箭头表示网络流量。在这个假设的例子中,最明显的是,来回发送消息需要花费多少时间。在绘制整个页面所需的360 ms中,仅花费60 ms来处理客户端或浏览器端的请求。总共需300 ms,或者说超过80%的时间用于等待消息在网络上传送。在此期间,Web浏览器和Web服务器都没有做太多事情,这段时间被浪费了,这是HTTP协议的一个主要问题。在120 ms处,浏览器请求图像1之后,它知道需要图像2,但是在发送请求之前,它需要等待连接空闲,要等到240 ms之后。这个过程效率很低,不过有很多方法解决,稍后你会看到。例如,大多数浏览器都会打开多个连接。关键是基本的HTTP协议效率很低。

大多数网站不可能只由两个图像组成,图2.2中所显示的性能问题,随着需要下载资源数量的增加会变得更严重。如果有一些较小的资源,相对于网络传输时间,客户端和服务器只花很少的时间去处理,这个问题会更明显。

现代互联网最大的问题之一是延迟而不是带宽。延迟是将单个消息发送到服务器所需的时间,而带宽是指用户可以在这些消息中下载多少内容。较新的技术一直在增加带宽(有助于解决网站内容增加的问题),但并不改善延迟问题(可以防止请求数量增加)。延迟受物理(光速)上的限制。通过光纤传输的数据,传输速度非常接近光速;无论技术有多大改进,速度都只能提升一点点。

Google的Mike Belshe做了一些实验[5],表明增加带宽的收益已经开始衰减。我们现在可以流式传输高清视频,但网速并没改观太多,即使是快速的连接,网站也需要几秒钟才能加载完。如果解决不了HTTP/1.1的根本性能问题,互联网就无法继续增长。在发送和接收HTTP消息时浪费了太多时间,尽管这些消息可能很小。

2.1.2 HTTP/1.1管道化

如第1章所述,HTTP/1.1尝试引入管道化,从而在收到响应之前并发发出请求,实现并行发送请求。初始的HTML仍然需要单独请求,但是当浏览器知道它需要两个图像时,它可以先后连续发出两个请求。如图2.3所示,在这个简单的示例中,使用管道化操作可以缩短100 ms时间,也就是1/3的时间。

图2.3 简单示例网站的HTTP管道化

管道化技术应该会对HTTP带来巨大的性能改善,但由于多种原因,它很难实现,易于出错,并且没有获得Web浏览器和Web服务器的良好支持[6]。因此,它很少被使用。没有一个主流的Web浏览器支持管道化技术[7]

即使管道化技术得到了更好的支持,它仍然需要按照请求的顺序返回响应。如果图像2可用,但必须从另一台服务器获取图像1,则图像2的响应会等待,即使应该可以立即发送图像2。此问题被称为队头(HOL)阻塞问题,在其他网络协议及HTTP中很常见。我们在第9章讨论TCP队头阻塞问题。

2.1.3 网络性能瀑布流图

图2.2和图2.3中所示的请求和响应流通常以瀑布图的形式显示,左侧是资源名,右侧是使用时间。对于大量的资源,瀑布图比图2.2和2.3中的流程图更容易阅读。图2.4显示了我们假想的示例网站的瀑布图,图2.5显示了使用管道化技术的相同网站的情况。

图2.4 示例网站的请求瀑布图

图2.5 示例网站使用管道化技术的瀑布图

在这两个示例中,第一条垂直线表示可以渲染初始页面的时间(称为开始绘制时间开始渲染时间),第二条垂直线表示页面何时加载完成。浏览器通常会在下载图像之前尝试绘制页面,并在稍后填充图像,因此图像下载通常在这两个时间之间。这两个例子都很简单,但实际应用会复杂得多,本章后面给出了一些案例。

可以使用各种工具,包括WebPagetest[8]和Web浏览器开发者工具(在第1章简单介绍过)生成瀑布图,这样查看Web性能非常方便。大多数工具会将每个资源的总时间分解为不同部分,例如DNS查找和TCP连接时间,如图2.6所示。

图2.6 webpagetest.org上的瀑布图

此图提供了比简单瀑布图更多的信息。它将每个请求分成几个部分,包括:

• DNS查询

• 网络连接时间

• HTTPS(或SSL)协商时间

• 请求的资源分类(并且还将资源负载分成两部分,用于请求的颜色较浅,用于响应的颜色较深)

• 加载页面各个阶段的各种垂直线

• 其他图表,显示CPU使用率、网络带宽,以及浏览器工作在哪个主线程中

这些信息对于分析网站的性能非常有用。本书会大量使用瀑布图解释相关概念。