前端监控体系与性能平台
对于线上应用,除了前期的开发和设计,上线后的维护同样重要,其中就包括监控体系的搭建。搭建前端监控体系主要是为了解决两个问题:如何及时发现问题?如何快速定位并解决问题?
一个完整的前端监控体系包含:数据采集(埋点与收集)→ 性能 SDK → 数据上报 → 性能平台(数据处理 + 可视化)→ 监控预警 → 问题诊断 → 效果评估。
一、监控什么数据
监控数据从五个维度采集,覆盖页面访问速度、稳定性、外部服务调用等情况:
| 数据类别 | 关注点 | 采集方式 |
|---|---|---|
| 生命周期数据 | 页面性能、访问情况 | PerformanceTiming、框架生命周期 |
| HTTP 测速数据 | 外部服务调用、性能优化 | PerformanceTiming |
| 系统异常数据 | 系统稳定性、异常问题 | window.onerror、error 事件 |
| 用户行为数据 | 页面稳定性、访问情况 | DOM 事件监听 |
| 用户日志 | 问题排查 | 埋点输出 |
1. 生命周期数据
前端应用的生命周期指页面加载的关键时间点,可通过 PerformanceTiming 获取:
// 页面加载关键时间点
const timing = performance.timing;
navigationStart; // 页面跳转
domLoading; // DOM 开始解析
domInteractive; // DOM 解析完成
domContentLoadedEventEnd; // DOMContentLoaded 完成
loadEventEnd; // 页面加载完成但框架化后,DOMContentLoaded、readystatechange 失去原本作用(页面渲染由框架控制),更多在框架生命周期钩子中收集(如 Vue 的 mounted、React 的 componentDidMount)。也可以结合 MutationObserver 监听 DOM 变化:
const observer = new MutationObserver((mutations) => {
console.log(`时间:${performance.now()},DOM 树变化类型:`);
mutations.forEach((m) => console.log(m.type));
});
observer.observe(document, { childList: true, subtree: true });2. 系统异常数据
常见前端异常包括:逻辑错误、代码健壮性问题、网络错误、系统错误(运行环境兼容性)、页面内容异常。前四类可通过 window.onerror、error 事件、XMLHttpRequest.status 等拦截上报:
window.addEventListener('error', (event) => {
// 收集错误信息并上报
reportError({
message: event.message,
stack: event.error?.stack,
source: event.filename,
line: event.lineno,
column: event.colno,
});
});
window.addEventListener('unhandledrejection', (event) => {
reportError({ type: 'unhandledrejection', reason: event.reason });
});页面内容异常一般通过回归测试、UI 测试在上线前避免,或通过观察用户操作数据、页面访问数据异常来辅助判断。
3. 用户行为数据
包括页面浏览量/点击量、用户停留时间、访问入口、页面操作行为。通过 DOM 事件监听、页面加载情况获取。用户行为数据既能监控页面功能是否正常(功能异常必然导致点击量变化),也能分析用户操作链路。
4. 用户日志
异常定位依赖日志。可通过装饰器、方法劫持等方式自动打印输入参数、执行信息和输出参数。日志存放方式:上报服务器(成本高、可能丢失)或本地存储(依赖用户提交),可两者配合。
二、数据埋点
数据埋点有三种主流方案:
| 方案 | 特点 | 优点 | 缺点 |
|---|---|---|---|
| 代码埋点 | 手动在业务代码中埋点 | 灵活、准确 | 接入和维护成本高 |
| 可视化埋点 | 通过可视化界面配置 | 成本较低 | 灵活性中等 |
| 无痕埋点 | 固定 SDK 自动采集 | 成本低、接入快 | 自定义能力弱 |
实际使用中常将多种方案配合使用,如用无痕埋点采集基础数据,用代码埋点补充个性化需求。
无论哪种方式,都需要对数据进行标准化处理(按与服务端约定的协议格式转换),并配合本地缓存避免用户关闭应用、浏览器异常导致数据丢失。
三、性能 SDK 设计
性能 SDK 将采集代码和上报策略封装在一起,为公司各业务提供统一的性能统计能力。设计需满足两个要求:接入简单易用、运行平稳高效。
1. API 设计
将首屏、白屏、卡顿采集封装为统一 API:
- FMP API:首屏采集(
calculateScore分数计算、calFinallScore变化率计算、fmpImg首屏图片时间,后者独立抽为 util) - FP API:白屏采集
- BLOCK API:卡顿采集
- Extension API:扩展数据(如加载瀑布流,将首屏细分为 DNS、TCP 等时间)
最终封装为 Perf API 统一调用,先做环境兼容性判断(是否支持 window.performance)。
接入方式:
// npm 包方式
npm install @common/Perf -S;
import { perfInit } from '@common';
perfInit();
// 外链方式
// <script src="https://s1.static.com/common/perf/static/js/1.0.0/perf.min.js"></script>
try {
perfInit();
} catch (err) {
console.warn(err);
}提供帮助文档(接入示例、QA、调试参数 PERF_DEV_MODEL)可提升易用性,让工程师接入时能快速定位初始化失败、采集异常、请求参数错误等问题。
2. 运行设计
- 兼容性策略:用原生 JavaScript 做指标采集,实现跨技术栈(React/Vue)复用;不同终端(PC/移动/小程序)通过适配层抹平差异(如小程序用
minaFMP,其他端用FMP)。 - 容错机制:SDK 自身报错用
try/catch捕获并上报异常平台,且不能因 SDK 报错影响页面运行。 - 自测与 QA:按用户 top10% 机型和浏览器类型自测;升级时无论功能大小都做冒烟测试。
四、上报策略
1. 日志数据过滤
上报前过滤两类异常数据:计算错误的异常数据(负值、非数值)和合法但异常的极大/极小值(如 15s 以上的首屏时间)。负值会严重拖低首屏时间;字符串类型数值(如 "200")在计算时会出现 "200"+30=20030 的错误。过滤到的异常数据记录日志并上报异常平台。
2. 数据抽样
根据日活决定是否抽样:日活 10 万以下无需抽样;千万级日活必须抽样(如 58 同城做 10% 抽样)。业界也通过服务端下发抽样率动态控制,如双十二日活激增时抽样率从 10% 降到 5%,降低统计服务器负载。
3. 上报机制
- 按网络能力:强网(4G/WIFI)直接上报,弱网(2G/3G)本地存储、延时到强网再上报。
- 按 App 状态:空闲时上报,忙碌时等闲时(如凌晨 2-3 点)上报。
- 批量上报:默认消息达到 30 条才上报,或只在 App 启动时上报。
- 接口选择:建议优先使用 native 接口上报,可复用客户端请求连接,支持延时/批量上报。
4. 上报时机(前端通用)
| 时机 | 说明 |
|---|---|
| 定期/定量上报 | 本地缓存,达到一定数量或固定时间间隔打包上传 |
| 关键生命周期上报 | 异常触发时、用户退出程序前上传 |
| 用户主动提交 | 引导用户主动上传本地数据和日志 |
五、性能平台架构
性能平台是 Web 系统,包含后台数据处理和前台可视化展示两部分。
1. 技术架构
数据接入层 → 数据计算层 → 存储层 → 平台层
(Node.js) (Kafka/Spark/ (MySQL/ (React/AntV/
Hive/HDFS) MongoDB) Less)- 数据接入层:接收 SDK 上报数据,做协议转换后作为生产者写入 Kafka。
- 数据计算层:作为消费者从 Kafka 读数据存 Hive,用 Spark 做数据计算。
- 存储层:MySQL(账号权限、关注业务模块表)+ MongoDB(单条性能数据)。
- 平台层:React + Ant Design + AntV 可视化,nginx 做 Web Server,compression 做 Gzip。
2. 数据处理流程
第一步,入库:SDK 上报数据经后端(Node.js Controller)处理,URL 解析成 key-value,删除空数据、舍弃异常数据,写入 Kafka。使用 Kafka 而非直接入库 Hive,是为了应对高并发流量洪峰和避免数据重复(消息队列消费后删除)。
第二步,数据清洗与计算:用 Spark 处理重复数据(去重)、缺失数据(按 Performance 数据补全,无法补全则舍弃)、错误数据(负值、超 10s 则舍弃)。然后计算首屏时间分布、秒开率(首屏 ≤1s 占比)、页面瀑布流时间(DNS/TCP/请求耗时/DOM 解析等细分)。
第三步,准备可视化数据:用 Node-schedule 定时从 Spark 取数据导入 MongoDB。
3. 可视化前台
- 大盘页:展示各业务性能简图(首屏时间、秒开率、采样 PV)。
- 详情页:补充秒开率、性能均值、白屏均值细节,以及终端分布(iOS/Android 比例),展示页面加载瀑布流帮助定位瓶颈。
六、监控预警
监控预警要求实时,因此数据清洗后一个分支用 Spark 计算,另一个分支用 Flink 实时计算。
预警流程:
- 超过阈值的数据(如首屏 >2s、判定为卡顿)标记为预警数据。
- 用 Node-schedule 定时任务将预警数据拉取到 MongoDB 预警表。
- 按严重程度分级报警:企业微信报警 → 邮件报警(node-mailer)→ 短信报警。
以手机列表页为例:性能标准是首屏 1.5s、秒开率 90%。超出 10% 标红并企业微信报警,超出 20% 邮件报警,超出 30% 短信报警。
注意:预警通知消耗通信资源,为避免浪费,一般只对 App 首页核心导航位等关键页面做监控预警。
灰度监控:上报数据时带上版本号,灰度过程中关注——错误告警是否有新增、全版本功能点覆盖曲线是否正常、分版本新旧版本转化率是否一致。可关联 BUG 管理系统自动生成 BUG 单。
七、问题诊断
发现性能问题后,先确认是共性问题还是个例问题:
- 共性问题:大量用户数据指标异常(如某网络下首屏均值超 3s)。通过性能平台的加载瀑布流定位具体瓶颈点(如某 JS 文件被阻塞)。
- 个例问题:偶发性因素(个人网络抖动、手机内存占用多、用户连代理),不需要专门优化,一般客服联系用户解决。
诊断清单(四个角度):
| 角度 | 说明 | 示例 |
|---|---|---|
| 全量 vs 增量 | 数据是否一次拉全量 | 列表页首屏拉 4 条,滚动再加载后续 |
| 同步 vs 异步 | 接口是否同步阻塞 | 并行请求导航和商品两个接口 |
| 实时 vs 缓存 | 数据是否必须实时 | 榜单/静态资源走缓存,价格/库存走实时 |
| 原片 vs 压缩 | 图片是否用原图 | 用 webp,或用低清图占位再优化 |
八、效果评估
性能优化的最终目标是提升业务数据指标。数据显示:沃尔玛在线网站页面加载时间每减少 1 秒,转化率增加 2%(前提是首屏时间远大于 1s,若已秒开提升有限)。
评估方式:AB 测试。将页面分为 A/B 两个版本(通过条件语句、模板或路由区分),对比优化前后的转化率:
// 通过 URL 参数区分版本
if (params.version === 'A') {
// 优化前的逻辑
} else {
// 优化后的逻辑
}
// 下单时带上 from=version 标记,统计埋点对比转化率AA 测试:在 AB 测试前,先做两个版本代码完全一致的 AA 测试,确保版本差异带来的波动率在万分之一以下,保证 AB 测试结果可信。
注意事项:性能优化项目一定要做好兼容性测试,特别是 Top 10 机型和弱网环境,避免出现兼容性问题导致转化率反而下降。
九、总结
- 前端监控体系解决「如何及时发现、如何快速定位」两个问题,形成"采集 → 上报 → 监控 → 预警 → 诊断 → 评估"的闭环。
- 性能 SDK 是监控体系的关键,设计要保证接入简单、运行平稳(兼容性、容错、自测)。
- 性能平台提供数据处理(Kafka/Spark/Hive)和可视化(大盘/详情页),为监控预警和问题诊断提供支撑。
- 最终用业务指标(如转化率)评估性能优化效果,通过 AB 测试验证。