背景
直观的说法就是网站的响应速度,它不仅仅是网站打开速度。网站性能涉及用户访问网站的整个流程中。
首先用户在浏览器端发出请求,其次在网络上对请求数据、响应数据的传输,最后在网站服务器端对请求数据进行处理(执行程序、访问数据库、文件等),并将结果返回。
网站的响应时间,是判断一个网站是否是好网站的重要因素之一。网页的响应时间越短,用户访问起来感觉会更为流畅,体验也更好。
LCP(Largest Contentful Paint)
衡量页面的加载体验,它表示视口内可见的最大内容元素的渲染时间。相比 FCP,这个指标可以更加真实地反映具体内容加载速度。比如,如果页面渲染前有一个 loading 动画,那么 FCP 可能会以 loading 动画出现的时间为准,而 LCP 定义了 loading 动画加载后,真实渲染出内容的时间。
FID(First Input Delay)
衡量可交互性,它表示用户和页面进行首次交互操作所花费的时间。它比 TTI(Time to Interact)更加提前,这个阶段虽然页面已经显示出部分内容,但并不能完全具备可交互性,对于用户的响应可能会有较大的延迟。
CLS(Cumulative Layout Shift)
衡量视觉稳定性,表示页面的整个生命周期中,发生的每个意外的样式移动的所有单独布局更改得分的总和。所以这个分数当然越小越好。
业界公认的监控素材主要由两方面提供: 真实用户监控(Real User Monitoring,RUM) 合成监控(Synthetic Monitoring,SYN)
真实用户监控一般搭配稳定的 SDK,会在一定程度上影响用户的访问性能,也给用户带来了额外的流量消耗。
合成监控的优点比较明显,它的实现比较简单,有现成成熟的解决方案;如果搭配丰富的场景和规则,得到的数据类型也会较多。但它的缺点是数据量相对较小,且模拟条件配置相对复杂,无法完全反映真实场景。
Lighthouse 原理介绍
前文提到,合成监控有成熟的方案,比如 Lighthouse。我们的方案也基于 Lighthouse 进行,这里对 Lighthouse 原理进行介绍。 Lighthouse 是一个开源的自动化工具,它提供了四种使用方式,分别是:
-
Chrome DevTools
-
Chrome 插件
-
Node cli
-
Node module
我们先通过 Chrome DevTools 来迅速体验一下 Lighthouse。在 Audits 面板下,进行相关测试,可以得到一个网址的相关测试报告,内容如下图:
这个报告是如何得出的呢?我们先来看 Lighthouse 的架构图:
- Driver(驱动器),根据Chrome Debugging Protocol协议与浏览器交互的对象;
- Gatherers(采集器),调用 Driver 运行浏览器命令后得到的网页基础信息,每个采集器都会收集自己的目标信息,并生成中间产物(Artifacts);
- Artifacts(中间产物),一系列 Gatherers 的集合,会被 Audits 使用,并计算得分;
- Audits(审计项),以 Artifacts 作为输入,进行性能测试并评估分数后得到的 LHAR(LightHouse Audit Result Object)标准数据对象。
对 Lighthouse 架构原理进行分析:
- 首先,Lighthouse 驱动 Driver,底层通过 Chrome DevTool Protocol 调用浏览器进行应用的加载和渲染;
- 然后通过 Gatherers 模块集合,获取收集到的 Artifacts 信息;
- Artifacts 信息在 Auditing 阶段,通过对自定义指标的审计,得到 Audits 结果,并生成相关文件。
- Lighthouse 会与浏览器建立连接,并通过 CDP 与浏览器进行交互;
- 通过 Lighthouse,我们可以自定义审计项并得到审计结果。
采用 Lighthouse 的后两种使用方式(Node.js cli/ Node.js 模块)进行性能跑分的,下面代码给出一个基本的使用方式:
const fs = require('fs');
const lighthouse = require('lighthouse');
const chromeLauncher = require('chrome-launcher');
(async () => {
// 启动一个 chrome,
const chrome = await chromeLauncher.launch({
chromeFlags: ['--headless']
});
const options = {
logLevel: 'info',
output: 'html',
onlyCategories: ['performance'],
port: chrome.port
};
// 使用 lighthouse 对目标页面进行跑分
const runnerResult = await lighthouse('https://example.com', options);
// `.report` 是一个 html 类型的分析页面
const reportHtml = runnerResult.report;
fs.writeFileSync('lhreport.html', reportHtml);
// `.lhr` 是用于 lighthous-ci 的结果集合
console.log('Report is done for', runnerResult.lhr.finalUrl);
console.log('Performance score was', runnerResult.lhr.categories.performance.score * 100);
await chrome.kill();
})();
上面的代码描述了一个简单的 Node.js 环境使用 Lighthouse 的场景。其中提到了 lighthous-ci,这是官方给出的 CI/CD 过程接入 Lighthouse 的方案。但一般在企业中,CI/CD 过程相对敏感,我们的性能守卫系统就需要在私有前提下,介入 CI/CD 流程,本质上来说是实现一个专有的 lighthous-ci。