读书笔记——

大型网站性能优化实践(从前端、网络、CDN到后端、大促的全链路性能优化详解)

作者:周涛明 张荣华 张新兵

第1章 基于用户体验的性能优化要素

1.1 页面用户体验的要素介绍

几个优秀Market的要素:

  • 商品丰富、质量由保证等
  • 信誉好、品牌影响力大等
  • 价廉物美等其他因素

衡量网站性能方面的用户体验要素:

  • 白屏
  • 首屏
  • 页面整体加载
  • 页面可交互
  • 功能交互响应

1.2 白屏实践

1.2.1 白屏时间的重要性

简单理解,即用户打开浏览器输入网站的URL后,从屏幕空白到第一个画面出来的时间,这个时间的长短将直接决定网站页面给用户的第一印象。

  • StartRender
  • FirstPaint

重要性:页面渲染的时间越短,用户等待的时间就越短,用户感知到的页面速度就越快,这样可以大大提高用户体验,减少新用户的跳出,提高留存率。反之,过长的等待时间,会让用户变得烦躁,更轻易跳出或者关闭这个网站。

1.2.2 白屏过程详解

每个步骤:

1. DNS Lookup

DNS Lookup即浏览器从DNS服务器中进行域名查询。浏览器解析域名拿到对应的IP地址后,才能和服务器进行通信。通常浏览器在加载页面的过程中,会进行很多次DNS Lookup操作,其中包括页面本身的域名查询,以及浏览器在解析页面HTML代码过程中,需要加载JS、CSS、Image等资源产生的解析。

通常在页面加载过程中会产生下列域名解析:

  • www.example.com,页面URL本身。
  • style.example.com,JS、CSS等静态资源请求。
  • img.example.com,静态图片请求。
  • ajax.example.com,各种站内的Ajax请求。
  • *.google.com,其他比如Google的站外请求。

DNS解析速度的优化策略有很多:

  • DNS缓存优化
  • DNS预加载策略
  • 页面中资源的域名的合理分配
  • 稳定可靠的DNS服务器

2. 建立TCP请求连接

浏览器针对各个域名进行DNS Lookup得到IP地址后,就开始建立TCP请求连接的过程。

两个要素理解TCP连接及传输的过程:

  • 网络传输链路建立
  • 数据传输确认

优化思路:

  • 基于不同的网络环境,优化数据包的大小,以减少数据因传输丢失或者被破坏产生的重传,从而提高传输效率
  • 网络传输链路的优化,对于大部分企业来说,是需要很大投入的。

3. 服务端请求处理响应

一个动态的HTML请求,通常Web服务器在接收到此类请求后,会做出下面一系列处理:

  1. Web服务器根据请求类型,将请求转发给自己注册该请求的应用服务器来处理。
  2. 应用服务器接收请求,分配给对应的代码单元处理。
  3. 从缓存、数据库、文件系统等获取数据。
  4. 基于业务进行的数据逻辑处理。
  5. 基于模板进行数据格式化渲染。
  6. 应用服务器将格式化渲染的数据返回Web服务器。
  7. Web服务器将最终响应(Response)到客户端的内容,经过Gzip压缩(通常网站管理员会开启这个配置)后,返回客户端。

对于中小型网站来说,重心可能主要放在数据获取过程的优化。其中对缓存、数据库处理的优化,可为网站页面带来较大的响应速度提升。

而对于有着亿级流量的大型网络平台,每一个过程的优化都可能带来质的提升。比如被很多人忽略的模板渲染过程,通过优化模板渲染逻辑,可使模板渲染速度提高一倍;或者通过调整Gzip算法及相应内容的代码结构,来提高Gzip压缩率、减小压缩包大小等。

4. 客户端下载、解析、渲染显示页面

具体步骤如下:

  1. 如果使Gzip包,则先解压为HTML。
  2. 解析HTML的头部代码,下载头部代码中引用的样式资源文件或者脚本资源文件
  3. 解析HTML代码和样式文件代码,这个过程会构造出两个树结构,即与HTML相关的DOM树,以及与CSS相关的CSSOM树。
  4. 通过遍历DOM树和CSSDOM树,浏览器依次计算每个节点的大小、坐标、颜色等样式,构造出渲染树。
  5. 根据渲染树完成绘制的过程。

理想的页面显示过程:

浏览器下载HTML后,首先解析头部代码,进行样式表下载,然后继续向下解析HTML代码,构造DOM树,同时进行样式下载。DOM树构建完成后,立即开始构造CSSDOM树。如果样式表的下载速度足够快,DOM树和CSSOM树就进入一个并行的过程,当两棵树准备完毕,即可开始构造渲染树,最后进行绘制。

而在真实页面解析过程中,浏览器通常会因为各种因素被阻断。

  1. HTML代码中的JavaScript代码会阻断DOM树的构造,因为浏览器认为这段JS代码可能会修改DOM结构,所以必须等待JS代码执行完毕,再恢复DOM树的构造过程,这是由浏览器的安全解析策略决定的,目前并没有指定某个JS代码不涉及DOM的属性。
  2. 浏览器必须等待样式表加载完成,才能开始构建CSSOM树。
  3. 还有一种特殊情况,浏览器在解析HTML时遇到JS代码,而此时CSSOM树还未构建完成,则浏览器会暂停脚本的执行,直到CSS样式文件下载完成,并完成CSSOM树的构建,才会重新恢复原来的解析。这也是由浏览器的安全解析策略决定的。

HTML中的内联JS代码执行最大的危害在于上面第三种情况提到的,即DOM树构建被阻塞的时间不是只有JS代码运行的时间,而是会加上样式资源文件下载和CSSOM树的构建时间,这时浏览器所进行的串行解析过程。

关于浏览器下载、解析、渲染显示页面的优化策略,根据渲染步骤,大概可以从以下几方面着手:

  • 优化HTML代码和结构,缩短HTML下载时间,加快HTML解析速度
  • 优化CSS文件和结构,缩短CSS文件下载时间和解析时间
  • 合理放置JS代码,避免前面第三种情况的出现,这也是最重要的。

1.3 首屏时间

1.3.1 首屏时间定义

首屏时间即代表页面在“第一个屏幕”中的内容完全展示出来的时间。

与白屏不同的是,我们并不能从浏览器的系统API中获取首屏时间。在真实网络环境中,我们通过模拟的方式来获取首屏指标;而在实验室环境中,我们则可以通过一些性能测试工具来获取。

First Paint和First Contentful Paint仍然为衡量页面加载期间关键的用户参与环节提供了极具价值的数据。在Chrome 60 Beta的最新特性中包含了关于Paint Timing API的描述,全新的Paint Timing API公开了捕获First Paint和First Contentful Paint的指标。

1.3.2 首屏时间的重要性

首屏时间在页面整体加载的过程中,在开始渲染(StartRender)和加载完成(Onload)的中间,可以针对渲染时间指标的缺陷做出很好的补充,能够帮助我们综合衡量页面的性能情况,更真实地反馈页面带给用户的性能体验。

1. 完整指标量化系统

2. 更加真实地反馈用户体验

70%以上的用户点击路径集中在首屏区域。

首屏内容的展示速度会直接影响用户的性能体验。

1.4 页面整体加载完成

页面加载完成又称为PageLoad,即页面相关资源(CSS样式文件、JS脚本文件、图片等)全部加载完成的时间。当这个时间点被触发时,意味着当前页面对于用户来说是可以进行安全交互的。

  • 8s规则
  • 4s规则

第2章 前端性能优化实践

2.1 延迟渲染

通常为了加快页面渲染的速度,基础的解决思路是,通过去除页面上除首屏以外的对于用户不可见的信息区块,让页面的DOM节点数更少、DOM树结构更简单,从而达到加快页面下载和渲染速度的目的。

然后使用懒加载异步化请求、BigPipe等方案,动态加载这些不可见的信息区块。

考虑BigPipe方案的实施成本,大部分情况下,会使用懒加载异步化请求的方案对页面进行优化。

2.1.1 挑战和困难

问题:页面的主体部分不能再使用异步化请求的方式分割加载页面信息。

在服务数据查询请求的优化中,强调的是对于查询请求资源次数的优化,而不是查询结果的大小。

2.1.2 解决方案

目标页面的渲染性能瓶颈在于,页面DOM树节点数过多,导致在DOM树和Render树构建上所消耗的时间过多,从而使页面渲染性能不够高。

方案:减小页面首次渲染时的DOM树节点数,并且在不修改服务端输出逻辑的前提下进行。

方法:可选择使用TextArea来存放首屏以下的结果对应的HTML代码。存放在TextArea中的HTML代码,浏览器会解析识别为TextArea内容,而不会被当作DOM节点进行解析。

2.2 SEO Ajax

2.2.1 挑战和困难

针对SEO页面的性能优化,遇到的问题:

  • 针对爬虫爬取收录的页面,页面内容必须同步展示。
  • HTML代码和实际展现的内容要保证一定程度的一致性,否则有被认作作弊页面的风险。

在同步展示的要求上面,服务端要在一次请求过程中,把整个页面所有的内容都计算完毕,这就导致了页面在服务端的响应会消耗很多时间。同时一致性的要求,使得浏览器端方面,我们也不能轻举妄动,极大地限制了各种优化方案的使用。

2.2.2 解决方案

Google官方提供了一个称为Ajax crawlable scheme的Ajax爬行方案,是Google为了帮助爬虫抓取网络上越来越多的富应用页面产生的内容。

1. Ajax crawlable scheme细节概括

简单地说,整个解决方案是这样工作的。爬虫在页面中发现pretty Ajax URL(基于约定,URL中包括一个”#!”这样的锚点)。接着爬虫会对这个URL做简单的修改,来表明意图:我是来抓取快照的。然后请求服务器。这个时候服务器返回一个包含全部内容的页面快照,由爬虫进行处理。而在搜索引擎结果中,只会展示原先的pretty Ajax URL。

在实际方案运用中,会有两种不同的实现步骤:

  • 通过改造URL,向爬虫表明页面实现了Ajax crawlable scheme。
  • 通过页面meta标签,向爬虫表明页面实现了Ajax crawlable scheme。

2. 改造URL

3. 页面meta

如果Google提供的方案可行,它将会带来很大价值:

  • 可以放心使用Ajax异步化方案,而不担心影响SEO。
  • 可以基于此方案,进行更深入的前台和后台优化。
  • 采用此方案后,针对终端用户的响应和爬虫的抓取响应,可以在后台架构上做分离。在架构分离的前提下,针对终端用户,提供实时信息的响应;针对爬虫,提供一定时间缓存版本的响应。从而提高对爬虫的响应速度,最终减小来自爬虫的抓取压力。

4. 风险

验证了方案的可行性

第3章 网站性能分析

3.1 快速了解网站性能

3.1.1 使用YSlow进行性能分析

YSlow遵守基于所有基础的性能最佳实践的规则,快速分析HTML文档代码组成。

《高性能网站建设指南》中12条基本规则:

  • 尽量减少HTTP请求
  • 使用CDN
  • 静态资源使用Cache
  • 启用Gzip压缩
  • JavaScript脚本尽量放在页面底部
  • CSS样式表放在顶部
  • 避免CSS表达式
  • 减少内联JavaScript和CSS的使用,尽可能使用外部的JavaScript和CSS文件
  • 减少DNS查询
  • 精简JavaScript
  • 避免重定向
  • 删除重复的脚本

对于一个常规的相对简单的页面来说,以上规则的检查足够了,但是一旦遇到包含大量JavaScript文件及复杂布局的页面时,很难通过YSlow来分析浏览器在页面解析、渲染各个阶段的时间,从而导致优化无从下手。所以接下来,我们看一下Google开源的优化工具PageSpeed。

3.1.2 使用PageSpeed进行性能分析

Google提供的优化工具PageSpeed除了有网站的入口,也能够以插件形式在Firefox和Chrome浏览器上运行。它的工作原理类似于YSlow,也是基于一些基础性能最佳实践规则来分析代码,然后提供一系列能够提高页面性能的优化方案建议。

PageSpeed也有它的独到之处。它除了能提供页面在请求加载层面的优化建议,还能提供页面在加载完成后的一系列解析渲染操作的各部分时间,比如:

  • 页面包含的JavaScript代码的执行时间
  • 合理高效的CSS样式代码的建议
  • 页面布局渲染的时间等

然而,在现实世界里,用户在浏览页面时的性能体验,并不一定如我们所预期的那样(在本地开发完成并通过性能检查工具检查确认为具有良好性能表现的页面,并不代表用户在真实网络中访问会具有相同的表现)。

所以我们需要有一种工具,能够帮我们漂洋过海,去了解某个特定地区用户访问网站的真是性能情况。

3.1.3 使用WebPagetest进行性能分析

WebPagetest通过浏览器访问,基于输入的Website URL,以及选择的国家城市、浏览器类型、网络带宽等信息,启动对应的远程服务器上的浏览器进行性能分析测试。他们提供的不同城市的性能分析测试,是通过真实的部署在对应城市的物理服务器来实现的,而不是通过其他类似代理或者虚拟机等方式模拟实现的。

除了常规的性能分析及优化建议,WebPagetest还提供了页面加载过程的视频录制、关键节点截图、页面加载瀑布图等诸多重要信息。

几个重要的性能指标:

  • First Byte表示首字节响应时间,该时间可以综合反映出当前连接的网络状况和服务器的响应处理速度。
  • Start Render表示浏览器开始渲染的时间。
  • Speed Index表示一种在WebPagetest中自定义的性能指标。
  • Load Time表示加载时间。

其中Start Render、Speed Index、Load Time分别代表了前面提到的几个重要的影响用户性能体验的性能指标:

  • 白屏
  • 首屏
  • 页面整体加载

缺点:

  • WebPagetest很难对登录态依赖的Cookie的网页进行测试,基本上无法为测试页面设置正确的Cookie。
  • WebPagetest上的性能测试服务是由人工触发的

WebPagetest虽然能提供强大的性能分析服务,但作为免费的测试服务,提供的测试样本数量有限,测试结果也不能真正关联真实用户。

所以,如果希望网站能够持续为用户提供最佳的性能体验,就需要建立网站自身的性能监控系统。

3.2 真实用户前端性能监控

建立一个基础的真实用户前端性能监控系统,大致包含以下5个系统模块的设计开发工作:

  • 真实用户前端性能数据采集
  • 采集数据存储
  • 监控系统指标定义及加工计算
  • 数据分析、性能报表产出
  • 性能基线定义

3.2.1 真实用户前端性能数据采集

1. 终端环境数据

终端环境数据:

  • 设备信息,用于区分PC、Mobile、平板等不同设备
  • 操作系统
  • 浏览器
  • 地区/国家等

2. 基础性能指标数据

网络相关时间:

  • 页面域名解析时间(DNS Lookup Time)。
  • TCP建立连接时间(TCP Connection Time)。
  • 页面首字节时间,可理解为页面请求等待时间(Time To First Byte)。
  • HTML文档下载时间(HTML Download Time)。

浏览器渲染相关时间:

  • 页面开始渲染时间,即白屏等待时间(StartRender Time)。
  • 文档对象模型准备时间(Dom Ready Time)。
  • 页面加载完成时间(Page Load Time)。

3. 页面资源加载详情数据

页面加载包含的IMG、JS、CSS资源的时间消耗数据。