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

2.4 实际案例

之前我们讲过,对于多个连接,HTTP/1.1并不高效,但是情况有多糟呢?问题突出吗?下面我们来看一些实际案例。

实际网站和HTTP/2

当我开始写本书的时候,两个示例网站还都不支持HTTP/2。现在这两个网站都已经支持了,但这两个案例足够说明复杂网站使用HTTP/1.1时遇到的问题。这里所说的很多问题,在其他网站上也会遇到。HTTP/2越来越流行,任何一个被选择做案例的网站都可能在某个时间支持HTTP/2。我倾向于使用真实的、大家熟知的网站来演示HTTP/2解决的问题,而不是仅仅为了证明这些问题的存在而创建示例网站,所以尽管这些网站已经支持HTTP/2了,我还是使用它们作为例子。相对于它们所传达的概念,网站本身反而没那么重要。

为了重现在webpagetest.org上的测试,你可以设置--disable-http2来禁用HTTP/2(Advanced Settings→Chrome→Command-Line Options)。如果你使用Firefox,其中也有类似的选项[12]。当你使用HTTP/2时,这是用来测试HTTP/2性能变化的好方法。

2.4.1 示例网站1: amazon.com

之前讲的都是理论,现在看一个实际的案例。在www.webpagetest.org中输入www.amazon.com并执行,会看到如图2.10所示的瀑布图。本图说明了HTTP/1.1的很多问题:

图2.10 www.amazon.com的部分运行结果

• 首个请求是主页的请求,我们将其在图2.11中放大显示。

图2.11 首页的第一个请求

在发送请求之前,需要花费时间做DNS解析(创建连接、进行SSL/TLS HTTPS协商)。这个时间比较短(如图2.11所示,只要0.1 s多一点),但这增加了时间。对于首个连接,没有太多可以做的。该结果反映互联网运行的方式,如第1章所述。并且,尽管HTTPS算法和协议的提升可以减少SSL时间,但首个请求也是这些延迟的影响因素。我们能够做的是确保服务器响应迅速,且离用户近,以保持数据往返时间尽可能短。在第3章,我们会讨论CDN(Content Delivery Networks,内容分发网络),它能解决这个问题。

在初始化完成之后,有一个短暂的暂停。我无法解释暂停的原因,可能是因为开发者工具计时有一点不精确,或者是Chrome浏览器的问题。使用Firefox没有遇到这个暂停。然后,浏览器发出第一个HTTP请求(浅色的条),下载HTML(稍深颜色的条),解析,执行。

• HTML引用了几个CSS文件,它们也会被下载,如图2.12所示。

图2.12 CSS文件的5个请求

• 这些CSS文件托管在另外一个域(images-na.ssl-images- amazon.com),出于性能考虑,此域名和主域名不同。由于域名是独立的,所以在下载CSS文件时,需要从头开始,再来一次DNS查询、网络连接和HTTPS协商。请求1的创建时间在某种程度上是不可避免的,但第2个请求的创建时间是可以避免的。域名分片只是为了解决HTTP/1.1的性能问题。同时也要注意,在请求1中,当浏览器还在处理HTML页面时,CSS请求就开始了。尽管HTML页面在0.5 s之后才下载完,请求2在0.4 s前一点就开始了。浏览器不需要等整个HTML页面下载处理完才开始下载其他资源,它只要发现域名引用就开启新的资源请求(尽管由于连接创建延迟,新的资源在HTML下载完成时还没有进入下载流程)。

• 第三个请求是同一个域名上的CSS资源。由于HTTP/1.1在一个连接上同一时间只允许执行一个请求,因此浏览器创建了另外一个连接。这次省去了DNS查询时间(通过请求2,已经知道域名的IP地址了),但是在请求CSS之前,还需要进行耗时的TCP/IP连接创建和HTTPS协商。这个额外的连接存在的意义只是为了解决HTTP/1.1性能问题。

• 之后浏览器通过这两个已经创建的连接请求了另外3个CSS文件。图中没有说明为什么浏览器没有直接请求这些文件,这样会需要更多连接,花费更多资源。我看了Amazon的源码,在CSS文件请求之前有一个<script>标签,直到它执行完成后,才开始加载资源。这就解释了,为什么请求4、5、6没有和请求2、3同时发起。这一点很重要,后面我们会讲,HTTP/1.1的效率问题是互联网的其中一问题,这可以通过改善HTTP(如HTTP/2)来解决,但网络慢远远不止这一个原因。

• 在第2~6个请求中,加载CSS文件之后,浏览器认为接下来要加载图片,于是开始下载图片,如图2.13所示。

图2.13 图片下载

• 请求7中的首个.png文件,是由多个图标合成的精灵图(在图2.13中未显示),这是Amazon实现的另外一个优化。从请求8开始,加载了一些.jpg文件。

• 当有两个图片在请求中时,浏览器需要创建更多消耗性能的连接,以并行下载资源,如请求9、10、11和15。然后对请求14、17、18和19使用不同的域名。

- 在一些场景下(请求9、10和11),浏览器猜测可能需要更多的连接,所以提前创建连接,这就是为什么连接创建和SSL发生得更早,而且可以和请求7、8同时发出图片请求。

- Amazon添加了一个性能优化的方法,对m.media-amazon.com使用DNS prefetch(预解析)[13]。奇怪的是,没有对fls-na.amazon.com添加prefetch。这就是为什么,请求17的DNS解析过程发生在0.6 s,在发请求之前。在第6章我们会再次讨论这个问题。

在这些请求之后,页面还要加载更多内容,但是这些请求足以说明HTTP/1.1的问题了。所以不用查看整个网站的请求。

为了防止请求排队,需要创建很多连接。通常,这会导致下载资源花费的总时间翻倍。Web Page Test有个很方便的连接视图[14](如图2.14所示),我们可以通过该视图看看大致情况)。

图2.14 加载amazon.com的连接视图

可以看到,加载amazon.com主页需要20个连接,这还没算广告资源,它需要28个请求(图2.14中未显示)。images-na.ssl-images-amazon.com域名的前6个连接已经被充分利用了(连接3~8),但此域名的另外4个连接没有被好好利用(连接9~12)。有些连接(如连接15、16、17、18、19、20),只用来加载一两个资源,那创建这些连接的时间就有些浪费。

images-na.ssl-images-amazon.com域名上创建额外4个连接(为什么Chrome看起来突破了每个域名6个连接的限制)的原因非常有趣,我们需要研究一下。请求可以携带认证信息(经常使用cookie),也可以不带,Chrome通过不同的连接来处理这两类请求。出于安全上的考虑(参考浏览器如何处理跨域请求[15]),Amazon在对JavaScript文件的一部分请求中使用了setAttribute ("crossorigin","anonymous"),即不带认证信息,这意味着不使用现有的连接。所以,浏览器创建了更多的连接。这个属性对于HTML页面中的<script>标签直接发起的JavaScript请求来说,不是必需的。对于主域上托管的资源,这个变通的方法也不必要,这再一次说明在HTTP层面,域名分片可能效率低下。

Amazon的示例说明,在HTTP/1.1下,就算网站通过变通的方法进行了充分的性能优化,它还是会有一些性能问题。这些优化方法设置起来也很复杂。不是每个网站都想管理多个域名,都需要做精灵图,或者将JavaScript(或CSS)合并起来。也不是每个网站都像Amazon一样有能力、有资源做这些优化。更小的网站通常没做太多优化,性能受HTTP/1的限制影响较大。

2.4.2 示例网站2:imgur.com

如果不做这些优化,会怎样?我们以imgur.com为例来了解一下。因为它是一个图片分享网站,所以在主页会加载大量图片,而且不会将它们合并为精灵图。我截了WebPagetest瀑布图的一部分,如图2.15所示。

图2.15 imgur.com的瀑布图

我们跳过网页加载的第一部分(在请求31之前的部分),因为这部分和amazon.com有大量重复。可以看到,它使用最大6个连接去加载请求31~36,之后的请求在排队。当每6个请求完成后,开始新的6个请求,这就形成了图2-1所示的瀑布图。注意,这6个请求之间没有关联,可能在不同的时间完成(如瀑布图中后面的部分所示),但如果它们的大小接近,则它们常常同时完成。这就产生了6个请求互相关联的假象,但在HTTP层面,它们确实没有关联(除了它们共享同样带宽、连接同样的服务器之外)。

Chrome的瀑布图如图2.16所示。在该图中,问题更清晰,因为它同时计算了资源从可以加载到开始加载的时间。你能看到,对于后续的请求,在图片请求之前有一个很长的延迟(方框高亮显示),后面跟一个相对较短的下载时间。

图2.16 Chrome开发者工具中imgur.com的瀑布图

2.4.3 这个问题究竟有多严重

本章一直在讨论HTTP效率低下的问题,虽然存在一些变通的解决方案,但是,这些解决方案并不完善。为此,需要花时间和资金,需要理解如何实现、如何维护,而且它本身也有性能问题。开发的成本并不便宜,花时间兼容一个效率低下的协议虽然有必要,但是成本高昂(更不用说,很多网站没意识到他们网站性能对他们的影响)。很多研究表明,网站缓慢会导致用户离开,订单减少。[16][17]

你必须认识到,和其他性能问题想比,HTTP协议的问题有多严重。导致网站缓慢的原因很多,从网络连接的质量到网站的大小,再到某些网站可能使用荒唐的JavaScript文件数,再到越来越多的性能低下的广告、数据追踪服务,等等。尽管更高效和更快地下载资源可以解决一部分问题,但是很多网站还是会慢。很多网站清楚地知道HTTP协议对网站性能的影响,所以他们实现了一些优化HTTP/1.1性能的方法。但是因为这些方法复杂且难以理解,所以很多其他的网站没有实现。

另外一个问题是,这些解决方案也有一些限制。这些方案本身也会引入低效率的因素,随着网站内容和复杂度的增加,最终这些变通的解决方案也会失效。尽管浏览器在每个域名上打开6个连接,并且可以增大这个数,但这么做的收益较低,这也是为什么浏览器限制并发的连接数为6个,尽管站长们可以通过域名分片的方法来突破这个限制。

总体来说,每个网站都是不一样的,每个站长或者Web开发者都要花时间分析网站本身的性能瓶颈,并使用瀑布图之类的工具,查明网站受到HTTP/1.1性能问题的影响有多大。