前端性能监控-基础指标定义&计算

5,732 阅读4分钟

一、前言

最近在做性能监控相关的工作,将准备工作中涉及的资料进行一次整理。

二、性能监控的两种方式

2.1、合成监控

合成监控(Synthetic Monitoring,SYN),就是在一个模拟场景里,去提交一个需要做性能审计的页面,通过一系列的工具、规则去运行你的页面,提取一些性能指标,得出一个审计报告。

合成监控工具比较有代表性的是 LightHouse,这张图是对掘金首页进行的一次性能测试报告:

image

2.2、真实用户监控

真实用户监控(Real User Monitoring,RUM),就是用户在我们的页面上访问,访问之时就会产生各种各样的性能指标,我们把这些性能指标上传到我们的日志服务器上,进行数据的提取清洗加工,最后在我们的监控平台上进行展示的一个过程。

目前已有的第三方产品有:OneApm、听云、FrontJS、NewRelic 等等。

2.3、对比

对比项合成监控真实用户监控
实现难度及成本较低较高
采集数据丰富度丰富基础
数据样本量较小大(和业务量成正比)
适合场景支持团队自有业务,对性能做定性分析 ,或配合CI做小数据量的监控分析。作为中台产品支持前台业务,对性能做定量分析,结合业务数据进行深度挖掘。

这两种方式具体的优缺点可以参考 蚂蚁金服如何把前端性能监控做到极致 这篇文章。

三、RIAL 模型

google 开发者提出了一种 RAIL 模型来衡量应用性能,即:Response、Animation、Idle、Load。

image

同时,Google 还提出了一系列性能指标,比如First Contentful Paint、Speed Index、Largest Contentful Paint 等等,具体这些指标的含义,可以参考 前端性能优化指南[7]--Web 性能指标 这篇文章。

四、基础指标定义&计算

image

可以根据 PerformanceTiming API 中的字段处理后得到以下关键指标:

描述计算方式备注
First Paint Time,首次渲染时间(白屏时间)。fpt = responseEnd - fetchStart从请求开始到浏览器开始解析第一批HTML文档字节的时间差。
Time to Interact,首次可交互时间。tti = domInteractive - fetchStart浏览器完成所有HTML解析并且完成DOM构建,此时浏览器开始加载资源。
HTML加载完成时间, 即DOM Ready时间。ready = domContentLoadEventEnd - fetchStart如果页面有同步执行的JS,则同步JS执行时间=ready-tti。
页面完全加载时间load = loadEventStart - fetchStartload=首次渲染时间+DOM解析耗时+同步JS执行+资源加载耗时。
首包时间firstbyte = responseStart - domainLookupStart

其他指标:

描述计算公式备注
DNS查询耗时dns = domainLookupEnd - domainLookupStart
TCP连接耗时tcp = connectEnd - connectStart
Time to First Byte(TTFB),请求响应耗时。ttfb = responseStart - requestStart参见Google Development定义。
内容传输耗时trans = responseEnd - responseStart
DOM解析耗时dom = domInteractive - responseEnd
资源加载耗时res = loadEventStart - domContentLoadedEventEnd表示页面中的同步加载资源
SSL安全连接耗时ssl = connectEnd - secureConnectionStart只在HTTPS下有效

五、其他性能数据

5.1、FPS 数据

检测页面卡顿:可以使用定时器,检测时间间隔,间隔大于预期的时候表示卡顿。

对于卡顿的检测可以参考 如何评价页面的性能 这篇文章。

5.2、长任务时间统计

主要是使用 PerformanceObserver 对 longtask 事件进行监听:

var observer = new PerformanceObserver((list) => {
    var entries = list.getEntries();
    for (var i = 0; i < entries.length; i++) {
        console.log(JSON.stringify(entries[i], null, 4));
    }
});
observer.observe({
    entryTypes: ["longtask"]
});

输出示例:

{
  "name": "self",
  "entryType": "longtask",
  "startTime": 1390.31999999861, // 此为 metric 上报时的时间
  "duration": 999.0749999997206, // 该事件的耗时
  "attribution": [
      {
          "name": "unknown",
          "entryType": "taskattribution",
          "startTime": 0,
          "duration": 0,
          "containerType": "window",
          "containerSrc": "",
          "containerId": "",
          "containerName": ""
      }
  ]
}

详细参数说明:Long Tasks API

不过,这个方法只能检测到 longtask,不能检测到具体是哪个方法或哪个模块。这个需要更详细的埋点数据去和 longtask 产生的时间去做匹配,才能发现具体的 longtask 在什么位置。

5.3、慢加载追踪

在页面 onload 后,可以利用 performance.getEntriesByType('resource') 获取资源加载时间,超过阈值的时候,进行上报。

5.4、浏览器内存

可使用 performance.memory 进行数据采集。

5.5、用户特征数据

比如ip、userAgent 等,这里只说一下 ip 获取的方式:

var dom = document.createElement('script');
dom.src = "http://pv.sohu.com/cityjson?ie=utf-8";
var container = document.head;
container.appendChild(dom);
dom.onload = function () {
    container.removeChild(dom);
    console.log(JSON.stringify(window.returnCitySN, null, 4))
}
dom.onerror = function () {
    container.removeChild(dom);
}

输出示例:

{
    "cip": "xxx.xxx.xxx.xxx",
    "cid": "110000",
    "cname": "北京市"
}

六、注意事项

需要注意监控对页面本身性能的影响。

七、参考