跳到主要内容

认识

2024年04月25日
柏拉文
越努力,越幸运

一、认识


Web 监控 是一个全链路的监控体系, 包括数据采集、数据上报、数据分析以及根据分析结果进行针对性的调整、消息推送等。

  1. 数据采集包括页面性能数据异常数据用户行为资源数据个性化指标等数据采集的过程

  2. 数据上报: 上报方式上报时机上报优化

  3. 数据分析及优化: 性能数据分析、异常数据分析、用户行为数据分析

  4. 消息推送

衡量一个站点性能的好坏,我们通常看两个方面: 首屏性能页面加载以后整个交互的流畅程度。这两个指标的好坏,决定了站点是否可以吸引用户和留住用户。

为了能获得好的用户体验,我们常常需要对站点做性能优化。做性能优化,首先要对站点进行性能分析,寻找到底是哪个阶段性能较差,然后具体问题具体分析,找到对应的解决方案。而谈到性能分析,小编猜大家第一时间想到的是应该是打开浏览器 performancenetworklighthouse 面板,然后对页面加载过程进行分析吧。

诚然这是一个有效的办法,但在实际使用时却存在非常大的局限性。也许,我们自己访问站点的时候性能很好,没有什么问题,但用户在实际访问时,由于设备、网络、使用姿势、使用人数、使用时间段、服务吞吐量等原因,整个体验很可能会没有达到我们的预期。这种情况下进行性能分析就非常麻烦了,首先我们无法感知,其次我们也无法在本地直接复现出用户的使用情形。那怎么办呢?

这个时候,我们可以借助性能监控工具来处理这个问题,如 SentryFundebug (当然,也可以自研)。这类工具,可以在用户访问站点时,将首屏性能、用户交互涉及的一些指标数据通过接口上报给监控平台。监控平台接收到上报数据以后,对数据做汇总、计算,然后以可视化图表的方式展示。通过这些图表,我们就可以进行性能分析,找到影响用户体验的因素,非常方便。

二、加载模型


谈到性能优化, 就必须会提及的加载过程模型图:

Preview

这个加载过程模型,是 web 性能工作组 早在 2012 年就针对页面加载过程制定的,定义了从上一个页面结束,到下一个页面从开始加载到完成加载的整个过程。基于这个模型,我们可以获取到页面加载过程中各个阶段的耗时情况,然后分析出页面加载性能。

三、获取方式


3.1 window.performance.timing

最初,我们可以通过 window.performance.timing 这个接口获取加载过程模型中各个阶段的耗时数据。返回的是一个 UNIX 类型的绝对时间,和用户的系统时间相关,分析的时候需要再次计算。

var timing = window.performance.timing;

// 返回数据格式
{
navigationStart, // 同一个浏览器上下文中,上一个文档结束时的时间戳。如果没有上一个文档,这个值会和 fetchStart 相同。
unloadEventStart, // 上一个文档 unload 事件触发时的时间戳。如果没有上一个文档,为 0。
unloadEventEnd, // 上一个文档 unload 事件结束时的时间戳。如果没有上一个文档,为 0。
redirectStart, // 表示第一个 http 重定向开始时的时间戳。如果没有重定向或者有一个非同源的重定向,为 0。
redirectEnd, // 表示最后一个 http 重定向结束时的时间戳。如果没有重定向或者有一个非同源的重定向,为 0。
fetchStart, // 表示浏览器准备好使用 http 请求来获取文档的时间戳。这个时间点会在检查任何缓存之前。
domainLookupStart, // 域名查询开始的时间戳。如果使用了持久连接或者本地有缓存,这个值会和 fetchStart 相同。
domainLookupEnd, // 域名查询结束的时间戳。如果使用了持久连接或者本地有缓存,这个值会和 fetchStart 相同。
connectStart, // http 请求向服务器发送连接请求时的时间戳。如果使用了持久连接,这个值会和 fetchStart 相同。
connectEnd, // 浏览器和服务器之前建立连接的时间戳,所有握手和认证过程全部结束。如果使用了持久连接,这个值会和 fetchStart 相同。
secureConnectionStart, // 浏览器与服务器开始安全链接的握手时的时间戳。如果当前网页不要求安全连接,返回 0。
requestStart, // 浏览器向服务器发起 http 请求(或者读取本地缓存)时的时间戳,即获取 html 文档。
responseStart, // 浏览器从服务器接收到第一个字节时的时间戳。
responseEnd, // 浏览器从服务器接受到最后一个字节时的时间戳。
domLoading, // dom 结构开始解析的时间戳,document.readyState 的值为 loading。
domInteractive, // dom 结构解析结束,开始加载内嵌资源的时间戳,document.readyState 的状态为 interactive。
domContentLoadedEventStart, // DOMContentLoaded 事件触发时的时间戳,所有需要执行的脚本执行完毕。
domContentLoadedEventEnd, // DOMContentLoaded 事件结束时的时间戳
domComplete, // dom 文档完成解析的时间戳, document.readyState 的值为 complete。
loadEventStart, // load 事件触发的时间。
loadEventEnd // load 时间结束时的时间。
}

3.2 window.performance.getEntriesByType('navigation')

后来,window.performance.timing 被废弃,改用 window.performance.getEntriesByType('navigation')。返回的是一个相对时间,可以直接用来分析,非常方便。

不过,光有这些还不够。上面的这些指标,更多是面向开发人员来说的,如果从用户角度来看,不够形象,并且难以理解。实际上,从用户角度来说,用户更加关心页面何时开始渲染、何时渲染出主要内容、何时可以交互、交互否有延迟、页面视觉是否稳定。

3.3 performanceObserver

针对用户关心的这几个方面,官方也提供了对应的指标和相应的获取方式, 那就是 performanceObserver

四、Sentry 配置性能监控


4.1 安装

安装 @sentry/tracing

yarn add @sentry/tracing

npm install --save @sentry/tracing

4.2 配置

Sentry.init 方法内部添加性能监控配置项

import * as Sentry from "@sentry/react";
import { BrowserTracing } from "@sentry/tracing";

Sentry.init({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
integrations: [new BrowserTracing()],
tracesSampleRate: 0.2
});

注意,tracesSampleRate - 采样率是必不可少的配置项,它的值决定了性能指标数据上报的频率。如果 tracesSampleRate0.7, 那么用户在使用应用时,70% 的几率会上报性能数据,30% 的几率不会上报性能数据。注意,如果 tracesSampleRate 设置为 0,则不上报性能指标数据。 tracesSampleRate 最大值为 1。通过设置 tracesSampleRate,可以有效降低 Sentry 后端的压力。

五、Sentry 性能监控原理


简单来说,就是通过 window.performance.getEntriesperformanceObserver 这两个 api,获取用户在使用应用过程中涉及的 load 相关、fcplcpfidcls 等指标数据,然后通过接口上报。监控平台拿到数据以后,通过可视化图标的方式展示性能指标数据,帮助我们分析。

具体在做性能监控时,Sentry 将性能指标数据分为两个部分: 首屏加载相关数据和页面切换相关数据。

  1. 首屏加载

  2. 页面切换

5.1 首屏加载

首屏相关数据的上报过程非常简单, 具体如下:

  1. 应用加载时执行 Sentry.init 方法进行初始化。在初始化的时候,会通过 setTimeout 实现首屏完成以后再上报首屏性能指标数据。默认情况下,timeout1000 ms。有时我们应用的首屏时间可能超过 1000 ms,这样我们就无法获取完整的首屏数据。遇到这种情况,这个时候我们可以手动设置 timeout,具体如下:

    Sentry.init({
    dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
    integrations: [
    new BrowserTracing({
    idleTimeout: 3000,
    ...
    }),
    ],
    tracesSampleRate: 1.0,
    });
  2. setTimeoutcallback 中通过 window.performance.getEntriesperformanceObserver 获取性能指标数据,然后通过接口上报。

5.2 页面切换

页面切换相关数据上报过程也很简单,过程如下:

  1. Sentry.init 初始化过程中对 history.pushStatehistory.replaceStatewindow.onpopstate 方法进行覆写,拦截应用路由切换操作。

  2. 页面切换完成以后,通过 window.performance.getEntries 获取性能指标数据,然后通过接口上报。通过 performance.getEntries 获取性能指标数据时,Sentry 会记录上次上报时的 oldIndex。等到下次上报时,从 oldIndex + 1 开始获取性能指标数据。

这样,Sentry 性能监控最关键的一步 - 性能指标数据上报就完成了。接下来要做的就是打开 Sentry 监控平台,进行性能分析了。

参考资料


使用 Sentry 做性能监控 - 原理篇