web性能入门

高性能浏览器网络 --> 第三部分 HTTP --> 第十章 web性能入门


在一个复杂系统中,性能优化过程主要在于弄明白系统的独立子系统和层次之间的交互,它们各自都有自己的一系列限制和局限因素。之前,我们已经分别详细探讨了许多网络组件 -- 不同的物理传输方法和传输协议 -- 现在我们可以把我们的注意力转到更大的,web性能优化的端到端层面。
  • 延迟和带宽对web性能的影响
  • TCP对HTTP的限制
  • HTTP协议本身的特点和不足
  • Web应用的发展趋势和性能要求
  • 浏览器的限制和优化
不同层次交互的优化不像解方程,有固定的解,每一个层次都彼此依赖,存在很多可能的解决方案。没有确切的建议,也没确切的最佳实践,每个组件都在不断进化:浏览器变得越来越快,用户的连接配置也在不断改变,web应用也再不断扩展,变得更强大更复杂。
因此,在我们开始列举和分析各个性能最佳实践之前,退后一步并定义真正的问题是很重要的:现代web应用是怎么样的?有什么工具可以利用?如何测量web性能,哪一部分有助于性能提升,哪一部分又拖后腿?

超文本,网页,Web应用

在过去的几十年中,互联网的发展给了我们至少三种不同类别的体验:超文本,富媒体网页,交互式Web应用。不可否认,用户很难区分后面两者,不过从性能的角度来讲,我们同它们的对话方式,对它们的度量维度,性能的定义是不同的。


超文本文档

超文本是万维网的起源,普通文本加上一些基本的格式以及对超链接的支持。以今天的标准来看,这些不算什么,但它证明了,万维网的远见,以及它的伟大功能。


网页

HTML工作组和早期的浏览器厂商扩展了超文本定义,以支持额外的超媒体资源,比如图片,声音,增加了很多其它原语以支持更丰富的布局。网页的时代已经到来了,现在可以使用各种类型的媒体来产生视觉效果更丰富的布局:看起来很漂亮但大多不具有交互性。


web应用

JavaScript, 动态HTML,以及AJAX这些技术再次带来革新,使简单的网页变成交互性的web应用,它们能够在浏览器中对用户直接做出反应。这为第一个成熟的浏览器应用铺平了道路,比如Outlook Web Access , 迎来的脚本,样式表和标记复杂的依赖关系图的新时代。


一个HTTP 0.9会话只有一个文档请求,这对于交付单文档的超文本完全足够了,创建TCP连接,请求-响应,然后关闭连接。挖掘性能就是简单的优化短TCP连接上的单个HTTP请求。
网页的出现改变了交付模式,从单文档转变为交付文档加上独立子资源。因此,HTTP 1.0引入了HTTP元数据的概念(头,headers),而且使用多种性能导向原语对其进行增强,例如定义明确的缓存,keepalive等原语。现在,可能会同时使用多个TCP连接,关键性能度量已经不再是文档加载时间,而是网页加载时间,通常称之为PLT。

最简单的PLT的定义:浏览器中的加载指示器指明加载完成为止的时间。一个更偏技术上的定义是浏览器中触发onload事件的时间,这是当文档和所有独立子资源(Javascript, 图片等等)都加载完成时由浏览器触发的事件。

最后,web应用把简单的网页,转换为复杂的依赖关系图:标记定义基本的结构,样式表定义布局,脚本创建交互式应用并对用户输入做出响应,还可能更改样式和标记。

因此,网页加载时间,已经成为web性能事实上的标准,不过,它也是个越来越不充分的性能基准:我们不再创建网页,我们是在创建动态交互式web应用。现在,除了关心,甚至不在关心,如何测量加载每个资源的时间(PLT),还着重考虑与应用相关的问题:
  • 应用加载进度的里程碑是什么?
  • 什么时候发生第一次用户交互?
  • 用户应该参与哪些交互?
  • 用户的参与度和转化率?
你的性能优化策略是否卓有成效,就看你定义和迭代应用相关的基准和准则的能力了。应用相关的知识和测量是相当重要的,特别是事关你的底线目标和业务指标时。

DOM, CSSOM, and JavaScript

现代web应用中,复杂的脚本、样式表、和标记依赖关系图到底是什么意思呢?为了回答这个问题,我们需要快速浏览一下浏览器的架构,看看解析、排版、脚本这些流水线是怎么配合工作,把一个个像素绘制在屏幕上的。



解析HTML文档就是构建DOM(Document Object Model)树。CSS对象模型(CSS Object Model),就像另一个容易被人遗忘的表亲,也在并行构建。之后,这两者被结合起来,用于创建“渲染树”,接下来,浏览器有了足够的信息进行排版和绘制。自此,一切顺利。

然而, 不幸的是,这里我们必须介绍我们最喜欢的朋友,同时也是敌人: JavaScript。脚本的执行会产生同步doc.write操作并阻塞DOM解析和构建。类似的,脚本可能查询任何对象以计算它的样式。这意味着JavaScritpt也会阻塞CSS。因此,DOM对象和CSDOM对象的构建通常交织在一起:DOM构建无法继续,除非JavaScript执行完成,在CSSOM可用之前,JavaScript无法继续执行。

你的应用的性能,特别是首次加载和“呈现时间”直接与脚本、标记、样式表之间的依赖关系相关。顺便说一句,记得流行的“风格在顶部,脚本在底部”最佳实践吗?现在你知道为什么了!渲染和脚本执行被阻塞在样式表上;尽可能快的把样式呈现给用户。


现代web应用剖析


一个现代web应用究竟是啥样的?HTTP Archive能够帮助我们回答这个问题。该项目通过定期爬行top流行网站,记录并汇总分析,每个目标所用资源的数量,类容类型,头部等其它元数据,来跟踪Web的创建。
早在2013年,一个web应用的平均构成如下:
  • 90个请求,从15个主机获取数据,总的传输大小为1,311KB的数据
  • HTML: 10个请求,52KB
  • 图片:55个请求,812KB
  • JavaScript: 15个请求,216KB 
  • CSS:5个请求, 36KB
  • 其它:5个请求,195KB
在你读到这里的时候,前面这些数字可能都已经改变,变的更大了(Figure 10-2)。趋势是稳步攀升而且没有停下来的明显标志。然而,先不谈确切的请求数和千字节数,这些各个组件组成的数量值得我们思量思量:现在web应用平均已经超过了1MB,而且大于有来自15个主机的100个子资源构成。

不像桌面应用,web应用不需要独立的安装过程:键入URL,点击Enter,就会启动并运行!不过,桌面应用只付出一次安装成本,而web应用在每次访问时都要执行“安装过程”-- 下载资源,DOM和CSSOM构建,执行JavaScript。这也难怪web性能是一个发展如此迅速的领域,而且是个热门话题!几百个资源,数M数据,10多个不同的主机,所有这些都必须在几百毫秒内一起完成,以提供期望的即时web体验。

速度,性能,用户感知

速度和性能是相对的。每一个应用都会基于商业准则、应用环境、用户期望、需要执行的任务的复杂性来制定它的一系列需求。话虽如此,如果一个应用必须与用户进行交互,那么我们就必须规划和设计具体的,以用户为中心的感性处理时间常数。尽管生活节奏加快了,或者至少感觉如此,但我们反应时间却不会变化(表10-1),这与应用(在线或离线),或介质(笔记本电脑、台式机、或手机)的类型无关。

前面这张表解释了web性能设计的非官方经验法则:为了留住用户,应该在250毫秒内,呈现网页,或者至少提供点可见的反馈。


想要提供即时体验的应用,必须在几百毫秒内对用户输入提供能够感知到的响应。超过1秒,用户的注意力就会转移,10秒之后,除非有进度显示,否则任务就会被抛弃。
DNS查询,TCP握手,以及一个典型的网页请求带来的几个往返延迟,合计起来很容易就在网络开销上花掉100 - 1000毫秒。看Figure 8-2. 这也难怪那么多用户,特别是移动网络和无线网络用户,都抱怨网页浏览慢!

Web性能带来经济效益
速度是一项功能,不是简单的为了速度而追求速度。Google, Microsoft, Amazon广为认知的研究显示web性能可以直接转化为经济效益 -- 例如:Bing搜索页面上2000ms的延迟将使每用户收益减少4.3%。
类似的,Aberdeen对160个组织的研究表明网页加载时间延迟1秒将导致转化率减少7%,访问量减少11%,用户满意度降低16%!
更快的网站会带来更多的页面访问量、更高的参与度和转化率。不过,不要把这奉为圭皋,也不要以为公认的工业基准就没有错:要实际测量你的网站上性能带来的影响,对比你自己的转化目标。后面章节会将到怎么样测量。

分析资源瀑布

没有提到资源瀑布的性能讨论是不完整的。实际上,资源瀑布很可能是我们掌握最有见地的网络性能和诊断工具。每个浏览器都提供了一些查看资源瀑布的工具,也有一些伟大的在线工具,比如WebPageTest,它能够为各种各样的浏览器提供资源瀑布。

WebPageTest.org是一个开源项目,也是一项免费的web服务,它提供了一个用于测试网页性能的系统,有位于全球范围内多个地方的多台主机组成:浏览器运行在一个虚拟机上,而且是可配置的,

开始之前,有一点很重要,我们应该认识到,每个HTTP请求可以分为几个独立的阶段(Figure 10-3):DNS解析,TCP握手, TLS协商(如果需要),HTTP请求调度,接着是下载网页内容。这些各个阶段的可视化显示可能因浏览器而异(颜色),不过为了简单点,我们将在本章使用WebPageTest版本。你应该要很熟悉最喜欢的浏览器的各种颜色表示的意义。

仔细分析Figure 10-3,我们会发现下载Yahoo主页共花费了683ms,等待网络的时间超过了200ms,占到了请求总延时的30%!然而,文档请求仅仅只是个开始,我们知道,一个现代web应用还需要各种各样的资源(Figure 10-4)才能产生最终的输出。以加载Yahoo主页为例,浏览器将需要从30个不同的主机获取52个资源,总计482KB。
资源瀑布揭示了许多关于网页结构和浏览器处理流水线的重要的洞见。首先,我们注意到,当获取www.yahoo.com文档的内容的同时,新的HTTP请求被调度:HTML解析逐步进行,是浏览器可以提早发现需要的资源,并在需要是并行调度请求。因此,资源获取的顺序很大程度取决于标记的结构。浏览器可能优化一些请求,但是正是对文档中资源的逐步发现造就了不同资源的“瀑布效应”。
其次,注意“开始渲染”(绿色垂直线)发生在所有资源加载完成之前,以允许用户在网页创建的同时就可以开始同它进行交互。事实上,“文档完成”事件(蓝色竖线),也是在所有资源加载完成之前触发的。换句话说,浏览器加载指示器已经停止旋转,用户可以继续他的任务,但Yahoo!主页还在后台逐步填充其它内容,比如广告和社交小工具。

当讨论不同的网络性能指标时,前述例子中,首次渲染时间、文档完成时间、获取完最后一个资源的时间的不同很好的说明了上下文的重要性。我们应该跟踪这三个指标中的哪一个才对呢?没有一个单一的答案;要看应用!Yahoo!的工程师选择了优化网页,以利用逐步加载,从而使用户可以早点看到重要的内容,要这样做,他们必须应用应用相关的知识,哪些内容是关键的,哪些可以放后点。

何时,以怎样的顺序调度资源?不同的浏览器实现的逻辑是不一样的。所以,应用的性能在不同的浏览器之间差异很大。
提示:WebPageTest 允许你选择用于执行测试的浏览器版本,以及测试位置。

网络访问瀑布是一个强大的工具,可以帮助我们检查对网页和应用的优化的效果,以及应该优化的方面。前面讨论的分析和优化资源瀑布的过程常常称之为前端性能(front-end performance)分析和优化。然而,这个名字可能是个不幸的选择,因为它会误导很多人,使他们相信所有性能瓶颈都在客户端。现实中,JavaScript, CSS,以及渲染流水线都是资源密集型步骤,服务器响应时间和网络延迟("后端性能")对于优化资源瀑布相对不重要。毕竟,你不能解析和执行一个被阻塞在网络上的资源。
为了说明这个问题,我们只需要在WebPageTest上从resource waterfall view切换到connection view(Figure 10-5)。
在resource waterfall view中,每一条记录代表一个单一的HTTP请求,connection view 与此不同,每一条记录代表一个TCP连接的生命周期 -- 该例子中总共有30个TCP连接 -- 用于从Yahoo!主页获取资源。有什么特别之处吗?注意下载时间,蓝色表示的部分,只占了每个连接总延迟的一小部分:15个DNS查询,30个TCP握手,以及在等待接收每个响应的第一个字节时的很多网络延迟(绿色部分) -- 大部分的延迟是由这些部分组成。

很奇怪为什么有的请求只有绿色条(time to first byte)?很多响应都很小,下载时间可以忽略不计,因此就没有显示在图上。实际上,对很多请求而言,响应时间常常是由往返时间和服务器处理时间组成。

最后,我们把最好的留在了最后。真正的惊喜在the connection view的底部:检查Figure 10-5 中的带宽利用率图表。除了几个数据突发点,网络利用率是很低的 -- 看起来连接带宽并没有给我们带来限制!这是异常情况吗?还是个浏览器的bug?不幸的是,这两者都不是。结果证明,对于大多数web应用而言,带宽不是性能限制因素。相反,瓶颈是客户端和服务器之间的网络往返延迟。

性能支柱:计算, 渲染, 网络

一个web程序的执行首先涉及到三个任务:获取资源,网页布局和渲染,还有JavaScript执行。渲染和脚本执行步骤遵从单线程,交错执行模型。不能对产生的DOM执行并发修改。因此,优化和协调好渲染和脚本执行是极其重要的。
不过,如果浏览器被阻塞在网络,等待着资源到来,那优化脚本执行和渲染流水线也没多大用处。网络资源的快速而高效的交付是运行在浏览器中的每一个应用的性能基石。
但是,有人可能会问了,网络速度正在一天比一天快,所以这个问题不会自行解决吗?是的,我们的应用在不断变大,但是假如全球平均网速已经达到3.1Mbps而且在不断增长,正如每一个ISP和运营商广而宣传的那样,我们还用担心这个问题吗?不幸的是,你可能直觉上也知道,而且Yahoo!这个例子也说明,如果答案是“是”,那我们也不会再读这本书了。让我们来仔细看看。

更多的带宽作用不大

别着急;带宽当然是很重要的!毕竟,每一个本地ISP和移动运营商都在不断的提醒我们高带宽的诸多好处:更快的下载、上行、和流速度,速度可达【插入最近的数字】Mbps!
更高的带宽数据速率总是有好处的,特别是涉及大量数据传输的情况:视频和音频流,或者其它任何类型的大数据传输。然而,日常的网页浏览,需要从几十个主机上获取上百个相对较小的资源,往返时间就成了限制因素:
  • 观看Yahoo!主页上的高清视频受带宽限制
  • 加载和渲染Yahoo!主页受往返延迟所限
取决于你想要观看的视频的质量和编码,你可能需要几百Kbps到几Mbps的带宽容量 -- 例如,HD 1080p视频需要3+Mbps带宽容量。现在很多用户都可以达到这个速率,流视频服务,比如Netflix日渐流行也证实了这一点。那么,为何对于一个能够支持HD视频流的连接而言下载一个要小得多的web应用会是一个挑战呢?

性能瓶颈 -- 延迟

在前面的章节中,我们已经讨论了所有必需的主题,以为为什么延迟是日常网页浏览的限制因素打下良好的理论基础。然而,一张图胜过千言万语,我们来看由Mike Belshe,SPDY协议的创建者之一,所做的一个定量研究的结果(Figure 10-6),关于带宽变化和延迟变化对某些流行网页的网页加载时间的影响。


Mike Belshe所做的研究成为了Google开发SPDY协议的启动点,SPDY后来成为了HTTP 2.0的基础。

在第一个测试中,连接延迟固定不变,连接的带宽从1Mbps逐步增加到10Mbps。可以看到,一开始连接带宽从1Mbps升到2Mbps几乎是网页加载时间缩短了一半 -- 正是我们想看到的结果。然而,接下来,带宽的提升产生了收益递减。当带宽超过5Mbps时,就只有个位数百分比的改进了,带宽从5Mbps升到10Mbps,对网页加载时间的改进仅仅只有5%。
Akamai's宽带速度报告(“Bandwidth at the Network Edge”)显示,美国用户的平均带宽已经超过了5Mbps -- 很多国家也将达到这个数字,还有很多国家已经超越了这个数字。因此,可以推断,一个美国的平均消费者,假如他想要提升web浏览速度,通过升级带宽是收效甚微的。他可以更快的下载和上传大视频文件,但包含这些文件的网页的加载并不会显著变快:带宽作用不大。
然而,延迟实验情况就不同了:延迟每改进20毫秒,网页加载时间都有一个线性的提升!或许当我选择ISP时也应该考虑延迟,而不仅仅是带宽。

为了大大加快网络访问速度,我们应该寻找更多降低RTT的方式。如果我们能够把跨越大西洋的RTTs从150ms降到100ms会有什么效果?这对网络访问速度的改进效果比把带宽从3.9Mbps提升至10Mbps甚至1Gbps效果还明显。
另一个降低网页加载时间的方法是减少每次加载所需要的往返次数。如今,网页需要的服务器和客户端之间的往返次数通常都是固定的。往返次数大部分在于握手到开始服务器与客户端通信(eg, DNS, TCP, HTTP),还有有通信协议引入的往返(例如,TCP慢启动)。如果我们能够改进协议以更少的往返次数来传输这些数据,我们应该就可以改进网页加载时间。这是SPDY协议的目标之一。
                                                                                                                                                                                              -- Mike Belshe More Bandwidth Doesn't Matter (Much)
前面的结果可能令很多人感到惊讶,不过你应该想到的,因为它们是底层协议性能特征的直接结果:TCP握手,流控制和拥塞控制,丢包造成的线段阻塞(head-of-line blocking)。大部分HTTP速率流有小的,突发数据传输构成,然而TCP是优化用于长连接和块(bulk)数据传输的。大部分情况下,网络往返时间(RTT)是TCP吞吐量和性能的限制因素。因此,延迟也是HTTP和其它使用TCP的应用的性能瓶颈。

如果网络时大部分有线连接的性能限制因素,你可能直觉的意识到,它应该是无线客户端更重要的性能瓶颈:无线网络延迟非常高,所以移动web的网络优化优先级更高。

浏览器优化

现代浏览器可不是个简单的网络socket管理器,如果我们没有提到这一点,我们就失职了。性能是每一个浏览器厂商最主要的竞争功能之一,鉴于网络性能是如此关键,浏览器正在日益变得更智能:DNS预解析,预连接可能的目标,预期和优化网页上的关键资源,等等,对此,你应该不会感到惊讶。
每个浏览器厂商的确切的优化列表可能不同,但他们优化的核心都可以分为两个大类:
文档感知优化
网络栈集成了文档、CSS、JavaScript解析流水线以帮助识别关键网络资源并进行优先级划分,进行提早调度,使网页尽可能快的进入交互状态。这通常是通过给资源分配优先级,预读解析,还有一些类似的技术实现的。
预测优化
随着时间的推移,浏览器可以学习用户的浏览模式,并执行预测优化以尝试推测可能的用户行为。这样的优化包括预解析DNS,预连接可能的主机,等等
好消息是这些优化都由浏览器自动完成的,而且常常能够减少几百毫秒的网络延迟。但话说回来,理解为什么要做这些优化,以及这些优化的工作原理是很重要的,因为我们可以协助浏览器以帮助它加速我们的应用。大多数浏览器都使用四种技术:

资源预取和优化
文档,CSS,以及JavaScript解析能够给网络栈额外的信息以指明每个资源的相对优先级:会阻塞第一次渲染的资源被给予高优先级,同时,低优先级的请求可能被临时放在队列尾部。
DNS预解析
提前解析可能访问的主机名以为将来的一个HTTP请求避免DNS延迟。预解析的可以通过学习浏览历史触发,用户的动作比如鼠标悬停在一个链接上,或网页上的其它信号都可能触发预解析。
TCP预连接
DNS解析之后,浏览器可能根据推测打开一个TCP连接。如果猜对了,它就能消除另一个完整的网络往返延迟。
网页预渲染
有的浏览器允许你提示它下一个可能的目标,它能够在隐藏tab中渲染整个网页,如此,当用户发起浏览时,网页就能立即呈现。

想要深入了解Google Chrome是如何实现这些优化的,可以看High Performance Networking in Google Chrome

从外部看,现代浏览器的网络栈是个简单的资源获取装置,但在内部,它是一个研究如何优化web性能的精彩世界。我们怎样协助浏览器呢?首先,我们应该密切注意每个网页的结构和交付:
  • 关键资源,比如CSS和JavaScript应该能够尽快被发现
  • CSS应该尽早交付以避免阻塞渲染和脚本执行
  • 不重要的JavaScript应该被推迟以避免阻塞DOM和CSSOM构建
  • 解析器逐步解析HTML文档;因此为了最好的性能,文档应该被定期刷新。
此外,除了优化网页结构,我们还可以在文档中嵌入额外的提示,暗中告诉浏览器替我们执行某些优化:
<link rel="dns-prefetch" href="//hostname_to_resolve.com"> 1
<link rel="subresource"  href="/javascript/myapp.js"> 2
<link rel="prefetch"     href="/images/big.jpeg"> 3
<link rel="prerender"    href="//example.org/next_page.html"> 4
1 域解析指定主机名
2 预取关键资源
3 预取资源
4 预渲染指定网页
这些都是预测优化的提示。浏览器不保证执行,但它可以利用这些提示优化它的加载策略。不幸的是,并不是所有的浏览器都支持所有的提示(Table 10-2)


为Google Search 优化Time to First Byte(TTFB)
HTML是由浏览器逐步解析的,这意味着服务器能够频繁的刷新文档标记,也应该这么做。这样客户端可以尽快发现并获取关键资源。
Google Search是一个关于这种技术的益处的一个最好的例子:当一个搜索请求到来时,服务器立即刷新搜索页面的静态头,然后才去分析查询。毕竟,为什么要等呢,每一个搜索页面的头部都是一样的!然后,当客户端解析头部标记时,搜索查询被分派给搜索索引,一旦搜索结果准备好,文档的余下部分,包括搜索结果,就被发送给用户。至于网页头的动态部分,比如登陆用户的名字,是通过JavaScript填充的。


原文:http://chimera.labs.oreilly.com/books/1230000000545/ch10.html#BROWSER_OPTIMIZATION

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章