项目性能总结--性能系统 《一》

162 阅读4分钟

背景

直观的说法就是网站的响应速度,它不仅仅是网站打开速度。网站性能涉及用户访问网站的整个流程中。

首先用户在浏览器端发出请求,其次在网络上对请求数据、响应数据的传输,最后在网站服务器端对请求数据进行处理(执行程序、访问数据库、文件等),并将结果返回。

网站的响应时间,是判断一个网站是否是好网站的重要因素之一。网页的响应时间越短,用户访问起来感觉会更为流畅,体验也更好。

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 架构原理进行分析:  

  1.   首先,Lighthouse 驱动 Driver,底层通过 Chrome DevTool Protocol 调用浏览器进行应用的加载和渲染;
  2. 然后通过 Gatherers 模块集合,获取收集到的 Artifacts 信息;
  3. Artifacts 信息在 Auditing 阶段,通过对自定义指标的审计,得到 Audits 结果,并生成相关文件。 
  4. Lighthouse 会与浏览器建立连接,并通过 CDP 与浏览器进行交互; 
  5. 通过 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。