写点什么

三步法助你快速定位网站性能问题

发布于: 2021 年 04 月 22 日

​​摘要:本文给大家简单介绍了如何生成网站的性能分析报告。


本文分享自华为云社区《在瀑布下用火焰烤饼:三步法助你快速定位网站性能问题》,原文作者:Kagol  。

引言


性能,是一个问题。


每个项目成长到一定的规模,都几乎必然要遇到性能问题,当遇到性能问题时,我们是:

一脸懵逼,就知道很卡、很慢,不知道为什么,

还是,

能够快速洞察性能瓶颈,找到行之有效的优化方案。

取决于我们对性能的理解深浅,以及是否有一套好的工具和方法。


接下来给大家分享我自己在定位业务性能问题时常用的三步法,为了方便记忆,我把它总结为一句话:在瀑布下用火焰烤饼。


话不多说,喝口水直接开撸!


Performance 面板简介


介绍三步法之前,先来简单了解下 Chrome 开发者工具的 Performance 性能面板,以及性能分析报告的基本组成。

生成性能分析报告


以 DevUI 团队的掘金个人主页为例,使用 Chrome 浏览器访问:https://juejin.cn/user/712139267650141


然后按 F12 打开 Chrome 的开发者工具,选择 Performance 性能面板。


这时我们会看到一个简单的指引:



指引里面有两个按钮,上面的按钮是手动录制,下面的是自动录制,我们点击傻瓜式的自动录制,自动录制会自动刷新页面,在页面加载完成之后,生成该页面的性能分析报告,无需人工干预,非常方便。


等个几秒钟报告就生成好了,一眼看去,花花绿绿的,不知道从何看起?



性能报告的组成


我们对生成的性能分析报告做一个简单的面板分类,看起来就很清晰了。



工具栏


性能报告的顶部是一个工具栏(或者叫控制面板),里面有一堆按钮,我这边用得比较多的是前面三个,其中前两个在指引里已经介绍过了,第三个是用来清除报告的。


还有两个隐藏的功能也很有用,一个是模拟慢网速的,另一个是模拟慢 CPU 的,对移动端应用做性能优化可能会用到。



概览面板


工具栏下面是一个概览面板,显示了整个页面加载过程中的 FPS(Frames Per Second,每秒传输帧数),用来评估页面的流畅度,有大片红色说明页面可能存在卡顿。


FPS 下面是 CPU 处理各个任务花费的时间,再往下是网络请求的耗时,概览面板最下面是每一帧的截图。


线程面板


概览面板往下是线程面板,默认展开的是网络请求瀑布图,其他线程的详情都是收起的。


每个线程面板对性能分析都有价值,而我最常用的是瀑布图和火焰图,后面会重点分析这两个图,如何利用这两张图来分析网站的性能瓶颈。


内存面板


再往下是内存面板,内存面板需要在控制面板中手动打开,它是一个分类的内存占用折线图。


每条折线是一种任务随时间推移的内存占用:


  • JS 堆栈

  • 文档

  • HTML 节点

  • 事件监听

  • GPU 内存

详情面板


最下面是详情面板,首先看到的是一个饼图,这个饼图显示了各种类型任务的占比,这个非常有用,能否一眼看出什么类型的任务是性能瓶颈。


是资源加载还是脚本执行?是页面渲染还是图像绘制?又或者是空闲时间太长?


第一步:看饼图


刚才介绍 Performance 面板的组成时,提到了 3 个非常有用的性能分析利器,分别是详情饼图、请求瀑布图和主线程火焰图。

我把这三张图总结成一句话:在瀑布下用火焰烤饼

这句话也是我自己在做性能分析和优化时,屡试不爽的小技巧。


详情面板中的饼图用于展示各种类型任务的耗时占比。


主要有以下几种任务:


  • 蓝色是资源加载

  • 黄色是脚本执行

  • 紫色是页面渲染

  • 绿色是图形绘制

  • 白色是空闲时间


还是举刚才的例子。



从饼图可以看出占比最多的是脚本执行和空闲。


脚本执行时间长,我们大概可以猜测里面可能存在长任务(Long task);


而空闲占比多可能是等待服务器的响应时间太长。


饼图可以快速形成基本的判断,而具体原因则需要分析瀑布图和火焰图。


第二步:看瀑布图


我们来看下请求瀑布图,瀑布图和火焰图都是线程面板的一部分,瀑布图的横轴是时间轴,瀑布图上有很多五颜六色的色块,这些色块就是请求块,每种颜色代表一类资源:

  • 蓝色是 HTML 文件

  • 紫色是 CSS 文件

  • 黄色是 JavaScript 文件

  • 绿色是图片

  • 灰色是后台接口


我们主要关注那些长色块,长色块意味着耗时长,可能是性能瓶颈。

还是看下掘金个人主页的瀑布图。



总结瀑布图的特点


我们先观察这张图有什么特点,图形观察能力,相信大家小学就已经培养起来了,大致我们可以总结出以下比较明显的特点:


  • 特点一:大瀑布被分成三个小瀑布

  • 特点二:最左边的小瀑布大部分都是黄色色块,中间的小瀑布大部分是灰色色块,最右边的小瀑布大部分是绿色色块

  • 特点三:前两个瀑布之间有一段间距,中间什么色块都没有

  • 特点四:后两个瀑布被一个灰色色块的“尾巴”连在了一起

  • 特点五:顶部有一个超长的灰色色块


类似的特点我们还可以总结出很多来,但是这些特点说明了什么呢?能否帮助我们定位性能瓶颈呢?


回答这些问题需要我们对瀑布图以及浏览器原理有很多的认识,我们一步步来分析吧。


分析瀑布图的含义


我们按从左到右,从上到下的顺序进行分析,最左边有两个色块,一个灰色色块,一个蓝色色块,我们分别点击这两个色块,在详情面板看下它们的详情信息。


先看灰色色块



我们有注意到这个请求的启动器(Initiator)是一个 Chrome 插件:chrome://new-tab-page/omnibox.mojom-lite.js


因此我们不关注,接着看蓝色色块



前面我们已经介绍了,蓝色色块代表 HTML 文件,我们从详情的 Mime Type 为 text/html 也可以验证这一点。

我们滚动鼠标滚轮,把这个瀑布图放大,看这个蓝色请求块的细节



请求块的组成


通过查看细节图,我们有了新的发现:


每个请求块都由四部分组成:


  1. 左侧线:代表请求发送之前的时间(Before Request Sent)

  2. 浅色块:代表请求已经发送(Request Sent),直到服务器返回第一个字节给浏览器(TTFB, Time to First Byte)

  3. 深色块:服务器返回的内容全部下载到浏览器(Content Download)

  4. 右侧线:等待主线程处理(Waiting for main thread)


这个 HTML 文件是整个网页渲染的起点,成功请求并下载这个文件,才会有接下来的故事。


这个请求块的浅色块部分占比比较大,根据前面的介绍,浅色部分代表的是服务器的响应速度,浏览器已经早早地发出了请求,服务器却迟迟才给回应(第一个字节到达浏览器)。


中间可能是网络慢,也可能是服务器处理速度慢,需要具体排查,毕竟这个 HTML 文件不算大,才 111KBb,却花了 179ms。


对比另外一个文件 layouts.default.js,体积比它大 124KB,请求耗时却比它小一半多,才 74ms。(后来发现这个数据不稳定,这个 HTML 文件应该不至于构成性能瓶颈)


另外所有后续的请求都依赖于这个 HTML,没有它其他请求都不会发生,它是一个阻塞请求,性能必须要有保障。


发现可能的性能瓶颈


我们继续看右边的请求块,顶部那个超长的灰色块依然是 Chrome 插件的请求,我们不管,看下面那一堆黄色的请求块,这些都是 JavaScript 文件。


HTML 文件下载完了之后,就会开始一行一行解析其中的 HTML 标签,遇到设置了谁、src 属性的<script>标签,就会去下载 src 指定的 JavaScript 脚本文件。



从瀑布图可以看出,一共并行下载了 8 个 JavaScript 文件,它们的域名都是一样的:

sf1-scmcdn2-tos.pstatp.com

不是说 Chrome 浏览器对同一个域名,并行的请求数最大是 6 个吗?


不仅仅是 JavaScript 文件,下面还有 3 个同域名的图片资源,也是在并行请求的,也就是说几乎同时发起了 11 个请求。


这说明掘金的静态资源服务器升级到了 HTTP/2


HTTP/2 的多路复用可以实现一个 TCP 连接同时传输多个资源。


我们到 Network 面板里去看下这些 JavaScript 的请求详情,果然和我们猜测的一致,这一点必须给掘金点个赞👍



发一个某 86 网站和掘金的对比图,大家感受一下某 86 网站:



掘金:



虽然前者更像一个瀑布,但是我喜欢后者丝滑般的体验。


我们再来仔细看这 8 个请求,相信细致的你一定发现了一个现象:

  1. 它们的共同点除了刚才提到的域名一样外,这些请求块的左右线都很短

  2. 有三个特别长的请求块,分别是 1/5/8,需要格外关注


请求块的左右线都非常短是一个好现象,说明没有什么等待时间,所有时间都用在了传输数据上。

我们分别点击 1/5/8 请求块看它们的详情


请求块详情 1 大小:4KB 耗时:635ms5 大小:90KB 耗时:635ms8 大小:3.9MB 耗时:633ms


这非常奇怪,1/5 的资源大小和 8 的不在一个量级上,耗时却比 8 还多。


为了确定这是偶然的,还是必然的,我又录制了两次这个掘金个人主页的性能报告




这次和预期的基本一致,8 耗时比其他都长,这个 JavaScript 文件 3.9MB,太大了,很可能是性能瓶颈。


其他


让我们继续往下分析,黄色 JavaScript 色块下面一共有三种颜色的色块:


  • 紫色:CSS 样式文件

  • 绿色:图片文件

  • 灰色:字体文件(大小为 189KB)


这几个文件体积都不大,并且通过多次生成性能报告,发现这几个请求耗时都不如第 8 个 JavaScript 文件长,所以初步判断这些请求不构成性能瓶颈。


接着看中间那个瀑布,通过多次生成性能报告,发现中间瀑布并没有什么特别耗时的请求,不过不管生成多少次报告,有一点是确定的,就是这三个瀑布之间总是有些空白


这些空白到底说明了什么呢?


看完火焰图,相信你就会豁然开朗。

第三步:看火焰图


在看正式的火焰图之前,先来看一个瀑布图和火焰图放在一起的效果



看完这张瀑布和火焰的对比图,你一定看出了一个现象

瀑布图有空白的地方,火焰图就有颜色;瀑布图有颜色的地方,火焰图就是空白。


But Why?


要回答这个问题需要了解浏览器主线程执行任务的原理,以及火焰图是做什么的,别着急,让我们一步步来分析。

火焰图是什么


火焰图也是线程面板的一部分,它代表的是浏览器主线程的任务流:

随着页面的加载,时间的推移,主线程依次做了什么事儿


火焰图的横轴是时间,纵轴是一个个的宏任务。


每个宏任务下面若干个微任务,每个微任务下面有可能有很多子任务,依次类推。


由于有些任务的嵌套层级深,有些嵌套层级浅,所以呈现倒立的火焰状。


每种类型的任务颜色都不一样(无需记忆,有个大致的印象即可):


  • 解析 HTML Parse HTML:蓝色

  • 解析样式 Parse Stylesheet:蓝色

  • 评估脚本 Evaluate Script:黄色

  • 重新计算样式 Recalculate Style:深紫色

  • 绘制 Paint:深绿色

  • 执行微任务 Microtasks:黄色

  • Ajax 请求 XHR Load:黄色

  • 函数调用 Function Call:黄色

  • 触发定时器 Timer Fired:黄色


还是先大概看下掘金个人主页的火焰图



总结火焰图的特点


然后用我们小学就学会的看图找规律的技能,找到这个图有什么特点,大致扫一眼,我们就能总结出至少以下几个特点:

  • 特点一:总的来看两边是空白,中间有三个大火焰

  • 特点二:两边的两个大火焰正好对应瀑布图的两个空白(这就解释了为什么瀑布图的三个小瀑布之间有空白)

  • 特点三:有些宏任务特别长,并且背景色是红色的阴影线(而不是灰色)、右上角有一个红色的小三角形


多花点时间,可能我们还能有更多的发现,不过这几个是最显而易见的。


为了回答这些问题,我们需要近距离观察下火焰图。

分析火焰图的含义


既然火焰图代表主线程每个时间点都在干嘛,那么空白自然就意味着主线程没在干活,那么,它在干嘛呢?

它在等待,等待什么呢?

等待服务器返回一些必要的资源和数据


所以火焰图的空白处都是浏览器在等待服务器返回数据

寻找长任务


在所有主线程执行的任务中,我们尤其需要关注的是那些耗时特别长的长任务(Long task),这些长任务的特点前面已经说了:


背景色是红色的阴影线右上角有一个红色的小三角形


三个长任务 1s 钟就找到了



分析长任务


接下来是分析长任务,找到耗时长的具体模块/组件/方法。


我们把最右边最大的那个火焰放大,看看里面到底有些什么秘密。



放大之后,我们很快就发现这个耗时 591ms 的长任务,有 90%的时间都花费在了一个叫 init 的方法上,这个方法一共执行了 6 次,其中 3/4/6 耗时尤其长

第 n 个 init 方法详情 3 耗时:197ms4 耗时:93ms6 耗时:111ms


这个 init 方法到底是做什么的呢?


可能是挂在 Vue 组件的,会不会是有些组件特别大,里面的逻辑太复杂,这里需要掘金的前端给出答案。


再看下左边那个第二大的火焰,同样滚动鼠标滚轮把它放大



我们发现其中有一个 forEach 循环特别耗时,这个循环好像在计算什么东西,一共花了 150ms。


这个依然需要看下具体的源码才能找到问题的根因。



通过火焰图发现性能瓶颈的案例


最后给大家分享下我自己之前在 XBoard 看板项目中,通过火焰图发现一个依赖库的性能问题。

也是遵循一样的思路:


  1. 找到长任务

  2. 将长任务的火焰图放大

  3. 一层层往下找,直到找到一个耗时长的有名字的方法(现网大部分代码被压缩混淆了,看不出名字,开发环境会更方便定位到存在性能问题的方法)

  4. 在火焰图中点击这个方法,看详情面板中 Function 后的链接,点击这个链接,直接跳转到相应文件中的指定方法中

  5. 在源码中搜索这个方法名字,找到它

  6. 寻找解决方案


当时 XBoard 看板页有一堆长任务,我找了其中的 TOP3



然后将第一个长任务放大,很快就有了收获,我发现其中有一个叫 drawQrCode 的方法耗时比较长,一共花了 192ms。

接着通过查看详情,发现这是一个依赖库的方法,该依赖库定义了一个 drawQrCode 用来绘制二维码,而这个二维码其实不在看板页面上,而是需要通过鼠标 hover 到某个按钮上才加载出来。


所以当时解决的方案就是延迟 drawQrCode 方法的执行,即:

首页加载时,不执行 drawQrCode 方法,当鼠标移到相应按钮上时,才执行。



瀑布图和火焰图的关系

瀑布图和火焰图是相互补充、相互验证的关系。

瀑布图代表浏览器发起向服务器的请求,然后浏览器根据服务器返回的数据,通过脚本执行相应的逻辑和页面的渲染。


当瀑布图有请求块时,说明浏览器在向服务器请求数据,如果浏览器必须依赖这些数据来做下一步的页面渲染,那么在服务器返回数据之前,很可能浏览器就没事干,然后火焰图上出现空白,饼图也会出现空闲(Idle)。


当浏览器拿到服务器返回的数据时,主线程正在处理这些数据,并渲染页面,因此很可能就没法向服务器发请求,这时瀑布图就会出现空白。


所以

  1. 发现瀑布图出现空白,很可能存在长任务,需要找到具体的耗时方法,并进行优化


  2. 发现火焰图出现空白,很可能是某些后台接口慢或者存在超大静态资源,需要定位到慢的原因,并想办法优化

小结


本文先给大家简单介绍了如何生成网站的性能分析报告,以及这份报告的大致组成;


接着跟大家分享我自己在定位业务性能问题时,经常使用的三步法:在瀑布下用火焰烤饼;


从饼图中我们可以对网站的性能有一个大致的认识,从瀑布图快速地发现慢接口和大资源,而从火焰图中,我们可以细致地洞察到具体哪个模块/哪个组件/哪个方法可能成为性能瓶颈。


点击关注,第一时间了解华为云新鲜技术~

发布于: 2021 年 04 月 22 日阅读数: 18
用户头像

提供全面深入的云计算技术干货 2020.07.14 加入

华为云开发者社区,提供全面深入的云计算前景分析、丰富的技术干货、程序样例,分享华为云前沿资讯动态,方便开发者快速成长与发展,欢迎提问、互动,多方位了解云计算! 传送门:https://bbs.huaweicloud.com/

评论

发布
暂无评论
三步法助你快速定位网站性能问题