认识
一、认识
Web
监控 是一个全链路的监控体系, 包括数据采集、数据上报、数据分析以及根据分析结果进行针对性的调整、消息推送等。
-
数据采集包括页面性能数据、异常数据、用户行为、资源数据、个性化指标等数据采集的过程
-
数据上报: 上报方式、上报时机、上报优化
-
数据分析及优化: 性能数据分析、异常数据分析、用户行为数据分析
-
消息推送
衡量一个站点性能的好坏,我们通常看两个方面: 首屏性能和页面加载以后整个交互的流畅程度。这两个指标的好坏,决定了站点是否可以吸引用户和留住用户。
为了能获得好的用户体验,我们常常需要对站点做性能优化。做性能优化,首先要对站点进行性能分析,寻找到底是哪个阶段性能较差,然后具体问题具体分析,找到对应的解决方案。而谈到性能分析,小编猜大家第一时间想到的是应该是打开浏览器 performance
、network
、lighthouse
面板,然后对页面加载过程进行分析吧。
诚然这是一个有效的办法,但在实际使用时却存在非常大的局限性。也许,我们自己访问站点的时候性能很好,没有什么问题,但用户在实际访问时,由于设备、网络、使用姿势、使用人数、使用时间段、服务吞吐量等原因,整个体验很可能会没有达到我们的预期。这种情况下进行性能分析就非常麻烦了,首先我们无法感知,其次我们也无法在本地直接复现出用户的使用情形。那怎么办呢?
这个时候,我们可以借助性能监控工具来处理这个问题,如 Sentry
、Fundebug
(当然,也可以自研)。这类工具,可以在用户访问站点时,将首屏性能、用户交互涉及的一些指标数据通过接口上报给监控平台。监控平台接收到上报数据以后,对数据做汇总、计算,然后以可视化图表的方式展示。通过这些图表,我们就可以进行性能分析,找到影响用户体验的因素,非常方便。
二、加载模型
谈到性能优化, 就必须会提及的加载过程模型图:
这个加载过程模型,是 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
- 采样率是必不可少的配置项,它的值决定了性能指标数据上报的频率。如果 tracesSampleRate
为 0.7
, 那么用户在使用应用时,70%
的几率会上报性能数据,30%
的几率不会上报性能数据。注意,如果 tracesSampleRate
设置为 0
,则不上报性能指标数据。
tracesSampleRate
最大值为 1
。通过设置 tracesSampleRate
,可以有效降低 Sentry
后端的压力。
五、Sentry 性能监控原理
简单来说,就是通过 window.performance.getEntries
和 performanceObserver
这两个 api
,获取用户在使用应用过程中涉及的 load
相关、fcp
、lcp
、fid
、cls
等指标数据,然后通过接口上报。监控平台拿到数据以后,通过可视化图标的方式展示性能指标数据,帮助我们分析。
具体在做性能监控时,Sentry
将性能指标数据分为两个部分: 首屏加载相关数据和页面切换相关数据。
-
首屏加载
-
页面切换
5.1 首屏加载
首屏相关数据的上报过程非常简单, 具体如下:
-
应用加载时执行
Sentry.init
方法进行初始化。在初始化的时候,会通过setTimeout
实现首屏完成以后再上报首屏性能指标数据。默认情况下,timeout
为1000 ms
。有时我们应用的首屏时间可能超过1000 ms
,这样我们就无法获取完整的首屏数据。遇到这种情况,这个时候我们可以手动设置timeout
,具体如下:Sentry.init({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
integrations: [
new BrowserTracing({
idleTimeout: 3000,
...
}),
],
tracesSampleRate: 1.0,
}); -
在
setTimeout
的callback
中通过window.performance.getEntries
和performanceObserver
获取性能指标数据,然后通过接口上报。
5.2 页面切换
页面切换相关数据上报过程也很简单,过程如下:
-
在
Sentry.init
初始化过程中对history.pushState
、history.replaceState
、window.onpopstate
方法进行覆写,拦截应用路由切换操作。 -
页面切换完成以后,通过
window.performance.getEntries
获取性能指标数据,然后通过接口上报。通过performance.getEntries
获取性能指标数据时,Sentry
会记录上次上报时的oldIndex
。等到下次上报时,从oldIndex + 1
开始获取性能指标数据。
这样,Sentry
性能监控最关键的一步 - 性能指标数据上报就完成了。接下来要做的就是打开 Sentry
监控平台,进行性能分析了。