查看原文
其他

渲染百万网页,终于找到影响性能的原因了

CSDN 2021-04-25

编译 | 明明如月  责编 | 阿哲
出品 | CSDN(ID:CSDNnews)

参考链接:https://itnext.io/we-rendered-a-million-web-pages-to-find-out-what-makes-the-web-slow-72bbba9ade96

我们渲染了全球排名前 100 万个页面,跟踪我们能想到的所有性能指标,记录每一个请求的 URL 和请求产生的错误。据我们所知,这可能是第一个将网页性能、访问错误和页面脚本库关联在一起的数据集。我们将借助这篇文章帮助大家了解如何构造高性能的网站。
访问了 100 万个网页,每个页面 65 个指标、请求了 2100 多万个 URL,记录了 38 万 3 千个错误,记录了 8 千 8 百多万个全局变量。
如果你认为自己可以比我们分析的更好,可以从我们发布到 Kaggle 上的链接下载到我们的数据集自己动手分析。


为什么要渲染一百多万个网页?


人们普遍认为现在互联网比 15 年前更加缓慢而且存在的问题更多。
越来越多的 JavaScript 框架、Web 字体和 polyfill 抵消了更快的计算机性能、网络和协议给我们带来的提速。因此我们想通过实验验证是否真正如此,我们希望通过实验找出导致 2020 年网站的缓慢和崩溃的共同原因。
这个计划很简单:编写一个渲染排名前 100 万的域名的根页面 Web 浏览器的脚本,并记录每一个可以想到的可能影响性能的因素:页面渲染时间、请求计数、重绘、JavaScript 错误、使用的库等等。
有了这些数据,我们就可以可以研究不同影响因素之间的关系。研究哪些因素最有助于降低页面渲染时间?哪些类库与可交互时间(TTI)相关?最常见的错误是什么?
收集数据只需使用 puppeter 编写 Chrome 脚本,在周末启动 200 个 EC2 实例渲染 100 万个网页。


整体情况



图:根 HTML 文档的协议使用情况
实验研究表明,HTTP 2 比 HTTP 1.1 使用得更加普遍,HTTP 3 使用量非常少。
图:链接资源的协议情况
链接资源 HTTP3 协议的使用率是根 HTML 文档的 100 倍。为什么会是这样?因为所有的站点都链接了一样的内容:
图:链接次数最多的 URL
那么有些 JS 脚本被大部分网站引用,是不是就意味着浏览器会共享同一份缓存呢?其实并非如此:Chrome 86 之后,不同域名的请求不会共享一份缓存。火狐浏览器也计划实现相同的功能。Safari 浏览器也早已经将不同的域名缓存分隔开来好多年了。


什么让网络变慢:预测交互时间


如果我们能通过数据集和得到的加载时间分析出网页变慢的原因就好了。我们将研究域交互度( dominteractive ),即文档渲染到能够让用户与之进行交互所需的时间。
我们查看每个指标与域交互的相关性。
图:各种指标与域交互相关度
基本上每个指标都与域交互度呈现正相关的关系,除了 0.x 和 1.x 版本之外。这些指标中的许多指标之间也呈现正相关。我们需要一个更复杂的方法来了解导致高交互时间的各个因素。
图:时间维度的框图。橙色代表中间值
其中有些指标与时间相关,单位为毫秒。我们可以通过上述框图,研究浏览器渲染页面耗时的主要原因。导致长互动时间的各个因素的一种方法是做线性回归,我们从其他指标预测域交互度。
也就是说,我们给每个指标分配一个权重,将一个页面的域交互度时间建模为其他指标的加权和,再加上一些常数。优化算法设置权重,使整个数据集的预测误差最小化。通过回归发现的权重大小,可以告诉我们每个指标对页面加载缓慢的影响的大小。
开发者从回归算法中排除时间指标。如果我们花了 500 ms 建立连接,就会给域交互度增加 500ms,但这并不是我们想要的。时间指标从根本上说是结果。我们希望了解是什么原因导致了它们。
图:指标的回归系数,预测域交互性
括号中的数字是通过优化算法得到的回归系数,以毫秒为单位。虽然确切的数字应该有所保留(参见下面的注释) ,但是看到每个特性分配的比例也很有趣的。例如,该模型预测,对于交付主文档所需的每个重定向,速度会减慢 354 毫秒。每当主 HTML 文档通过 HTTP2 或更高的方式传递时,该模型预测交互时间将降低 477 毫秒。该文档每触发一次请求,预计会多出 16 毫秒。
我们通过一个简化的现实模型得到回归系数。交互时间实际上并不是由这些输入指标的加权和决定的。这个模型还无法发现有明显的因果关系的因素。混杂多个变量让分析变得更加困难。例如,如果通过 HTTP 2 加载主文档与通过 HTTP 2 加载其他请求相关,那么模型将把这个优势加入到 main_doc_is_http2_or_greater 或者更大的权重中,来加速来自主文档以外的请求。我们需要谨慎地将模型的结论与现实联系起来。


HTTP 协议版本对域交互有什么影响?


下面是一个有趣的场景,由用于交付根 HTML 页面的 HTTP 协议版本进行分割。
第一个请求的 HTTP 协议版本分割的域交互式框图。橙色的线是中间值,方框的位置在第 25到 75 百分位之间。括号中的百分比是使用此协议发出的请求的分数。
还有一小部分网站使用 HTTP 0.9 和 HTTP1.0。而且这些网站速度也很快。我们看到,即使协议已经变得更快了,但程序员却给浏览器提供更多的内容低效了这种提速。
这是用于交付根 HTML 页面的协议版本。如果我们看一下协议对文档中链接的资源的影响会怎样?如果我们按照协议版本对请求数进行回归,就会得到以下结果。

图:通过协议版本对请求数进行分析,预测域交互度
根据上图我们可以得出这样的结论: 将请求的资源从 HTTP 1.1 迁移到 HTTP2 访问速度可以提高 1.8 倍,而从 HTTP 2迁移到 HHTP 3 速度将降为原来的 0.6倍。那么,HTTP3 真的是一个较慢的协议吗?答案是否定的: 一个更可能的解释是 HTTP 3 很少见,通过 HTTP 3发送的少数资源 (例如 Google Analytics) 对域交互的影响大于平均水平。


内容类型对域交互的影响是什么?


让我们根据传输的字节数、传输的数据类型来预测交互时间。
图:由请求发起者传输的千字节的回归系数,预测域交互度
下面分析不同的请求类型的请求数。
图:请求发起者的请求数的回归系数,预测域交互度
通过上图可以看出,并非所有的请求都是平等的。由 link 元素(即 CSS、 favicon)触发的请求,以及由 CSS (即字体、CSS)、脚本和 iframe 触发的请求,都会大大降低请求的速度。通过 XHR 和 fetch 执行请求预示着比基准的域交互时间更快(可能是这些请求几乎总是异步的原因)。CSS 和脚本通常以渲染阻塞的方式加载,因此发现它们与较慢的交互时间相关并不令人惊讶。视频的请求也挺快。


经验教训


通过上述分析我们并没有发现新的优化技巧,但是分析帮助我们预计各种优化影响。得到以下经验:
  • 尽量减少请求。请求的数量比请求传输的字节数对性能的影响更大。
  • 对于必须发起的请求,如果可能的话,请使用 HTTP2 或者更高版本的协议。
  • 尽可能避免使用阻塞式请求,尽可能使用异步加载。




为了弄清楚页面上使用了哪些库,我们采取了以下方法: 在每个站点上我们重点关注全局变量 (即窗口对象的属性)。然后,每个出现次数超过 6000 次的全局变量都与一个 JavaScript 库相关联(如果可能的话)。这是一项艰苦的工作,但由于数据集也有每个页面的请求 URL,因此可以查看可变事件和 URL 请求之间的关系,这足以帮助我们确定哪个库将设置全局变量。无法准确认定和某个库油管的全局变量被忽略。这种方法在某种程度上不够精确。JS 库没有义务在全局名称空间中留下任何东西。当不同的库设置相同的属性时,会产生一些噪点,这种情况在作标记时会被忽略。
现在最常用的 JavaScript 库是什么?根据网上的各种会议和博客文章,你可能认为是 React,Vue 和 Angular 这三个。然而根据我们的排名,并非如此。


使用率最高的 10 个类库


图:查看类库使用情况的完整列表
正如你所见,古老的 jQuery 使用率最高。它在 2006 年首发,已经有 14年的历史。它已经经历了几百个版本的迭代。2006年进入 Web 2.0 的时代,这一年最常用的浏览器是 Internet Explorer 6,最大的社交网络是 MySpace,网页也开始支持圆角。JQuery 的主要优势在于它跨浏览器的兼容性更好。然而,14 年后的今天,我们的样本中依然有一半的网页加载了 jQuery。
有趣的是,2.2% 的网站因为 JQuery 没有加载而出错。
根据前10 名来看,我们的浏览器主要运行分析、广告和代码,以便与旧的浏览器兼容。不知何故,8% 的网站定义了一个 setImmediate/clearImmediate polyfill,实现一个无法被任何浏览器实现的特性。


预测类库的时间交互


我们将对数据库的数据进行一次线性回归,研究库与域互动度的关系。回归的输入是一个向量 x,x. length = = 库数,其中如果存在库 i,x [ i ] = = 1.0; 如果不存在库 i,x [ i ] = = 0.0。当然,我们知道域交互实际上并不是由某些库的存在或不存在决定的。然而,将每个库和加载速度之间进行建模,通过成千上万的例子进行验证,能够给我们带来一些有趣的发现。

通过回归系数得到交互式时间的最佳和最差库

图:通过回归系数预测域交互度
这里的负系数表示存在该库时模型预测的交互时间低于库存不存在时。当然,这并不意味着增加这些库会使你的网站更快,这只是意味着这些库的网站碰巧比模型建立的基准更快。这里的结果可能既有技术性,也是社会性因素。例如,用于延迟加载的库预示着交互时间较短。这可能是因为使用这些库的的程序员通过懒加载对性能进行优化的结果。

通过回归系数得到 onload 时的最佳库和最差库

我们可以重复上面的实验,但是这次预测的是记载时间。记载时间为窗口的 “load” 事件启动所需的时间,也是页面上所有资源加载所需的时间。我们用和以前一样的方式做一个线性回归。
图:通过回归系数得到 onload 时的最佳和最差库

通过回归系数得到 jsheapusedsize(JS对象占用的内存) 的最佳库和最差库

这里的预测是 JavaScript 使用的堆大小,以兆字节为单位。
网上很多人可能会认为:存在相关性并不等于存在因果关系。事实上,我们确实不能直接用这些模型得到因果关系。特别在问题涉及多种因素时,在解释这些系数时我们应该非常慎重。该模型将交互时间较慢的 982 毫秒与 jQuery 的存在联系起来,而且有一半的站点加载了这个脚本,这应该引起我们的关注。如果你正在优化你自己的站点,交叉引用它的依赖列表与排名和系数这里应该给你一个比较不错的参考,可以看到哪些依赖删除可以帮助你最大限度地降低资源消耗。
如果你对我们所爬的网站中发现的错误感兴趣,请参阅我们 JavaScript 错误分析这篇文章 。在这篇文章里,我们分析了网站中发现的错误,并讨论了这些错误对我们的启发,指导我们如何设计才更不容易出错。

更多精彩推荐

子计算还没搞懂,光子计算又要来统治世界?

程序员为教师妻子开发专属应用;2020 最佳开源项目出炉;中国构建全星地量子通信网|开发者周刊

“干掉”程序员饭碗后,OpenAI 又对艺术家下手了!

IntelliJ IDEA、Kotlin、PyCharm 背后公司 JetBrains 遭美国调查!

为什么 Netflix 这么强?网飞 CEO 哈斯廷斯跟陆奇摊牌了

GitHub 宣布拆“墙”,恢复伊朗开发者使用权!

开考!狮子,老虎,企鹅,技术圈的这些飞禽走兽你认识多少?

在看

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存