Web Vitals 自动化监控平台:从采集到告警的全链路落地(RUM 实战)
如果你只靠 Lighthouse 做性能优化,你会遇到一个现实问题:
- Lighthouse 是实验室(Lab)数据
- 用户体验是线上(Field)数据
线上性能好不好,不取决于“某次跑分”,而取决于:
- 真实用户的设备与网络
- 真实流量的页面分布
- 第三方脚本与运行环境差异
要把性能变成长期能力,你需要一套自动化监控平台(RUM):
- 采集:前端采集 LCP/INP/CLS(按页面/版本)
- 上报:稳定低开销的传输(sendBeacon)
- 处理:清洗与聚合(p75/p95、按设备/网络分维度)
- 展示:趋势图与回归对比
- 告警:阈值与异常检测(防止上线回归)
本文给你一条可以从 0 开始落地的路线。
1. 平台目标:你到底要监控什么
建议把目标写成三个层级:
- 指标层:LCP / INP / CLS
- 分析层:按页面、按版本、按设备、按网络
- 动作层:告警、回归定位、复盘
最常用的聚合方式:
- p75(Google 推荐口径)
- p95(反映长尾与弱设备)
2. 前端采集:用 web-vitals(或兼容实现)
2.1 最小采集代码(示意)
// plugins/web-vitals.client.ts(示意)
import { onCLS, onINP, onLCP } from "web-vitals"
function report(metric: { name: string; value: number; id: string; rating?: string }) {
const payload = {
name: metric.name,
value: metric.value,
id: metric.id,
rating: metric.rating,
path: location.pathname,
href: location.href,
ts: Date.now(),
}
navigator.sendBeacon("/api/vitals", JSON.stringify(payload))
}
export default defineNuxtPlugin(() => {
onLCP(report)
onINP(report)
onCLS(report)
})
关键点:
sendBeacon:尽量不影响页面主线程与卸载时机- 附带
path与ts:后续做聚合/趋势必需
2.2 采集时必须考虑的“维度”
建议至少附带:
path/route(页面维度)appVersion(发布版本,避免回归无法定位)deviceClass(粗粒度:mobile/desktop)connectionType(可选)
版本号的来源:
- 构建时注入(环境变量)
- 或使用 git commit sha(更可追踪)
3. 上报接口:稳定、幂等、低成本
RUM 上报接口建议满足:
- 接收 JSON
- 允许高并发
- 做基本校验与限流
示意(后端伪代码):
- 校验
name是否在允许集合 - 丢弃明显异常值(例如 value 负数或超出合理范围)
- 记录
userAgent(可选)
4. 存储与聚合:先做“够用”,再做“完美”
第一版最推荐的方式是:
- 用时序/分析型存储(或关系型表 + 定时聚合)
- 每天/每小时按维度聚合 p75/p95
典型的聚合表字段:
dateHourpathmetricNamep75p95countappVersion
你不需要一开始就做复杂的实时流处理。
5. Dashboard:让问题“可见且可对比”
一个可用的 Dashboard 至少要做到:
- 按页面看趋势(最近 7 天/14 天)
- 按版本对比(新版本 vs 旧版本)
- 能 drill down 到设备/网络维度
建议优先把“核心页面”做出来(而不是全站)。
6. 告警:防回归比追分更重要
告警不要一开始就做得很复杂,最实用的两类告警:
6.1 阈值告警(最简单)
- 当 p75 CLS > 0.1 持续 2 小时
- 当 p75 INP > 200ms 持续 2 小时
6.2 回归告警(更贴近发布)
- 新版本的 p75 比上一个版本提升超过 20%
回归告警的价值是:你能明确把问题与“某次发布”关联起来。
7. 上线自查清单(避免采集体系自己变成性能问题)
- 上报采样率可控(必要时对低价值页面采样)
- 上报不阻塞交互(优先 sendBeacon)
- 数据不包含敏感信息(不要带用户输入/完整 cookie 等)
- 后端有基本限流与大小限制


