跳到主要内容

用户体验度量-RUM

1. RUM vs 实验室

类型数据来源优点缺点
Lab(Lighthouse / WebPageTest)固定环境跑可重复、可对比不代表真实用户
RUM(Real User Monitoring)真实用户上报真实数据噪音多、数据量大

生产必须两者结合。

2. 核心指标

2.1 Core Web Vitals

  • LCP(最大内容绘制)< 2.5s
  • INP(交互响应)< 200ms
  • CLS(累积布局偏移)< 0.1

2.2 辅助

  • TTFB(首字节)< 800ms
  • FCP(首次内容绘制)< 1.8s
  • TTI(可交互时间)

2.3 业务指标

  • 关键页面加载时长
  • 关键操作响应时长(搜索、下单)
  • 错误率 / JS Error
  • API 失败率

3. 采集

3.1 web-vitals

import { onCLS, onINP, onLCP, onFCP, onTTFB } from 'web-vitals'

function send(metric) {
const body = JSON.stringify({
name: metric.name,
value: metric.value,
id: metric.id,
rating: metric.rating, // good / needs-improvement / poor
delta: metric.delta,
navigationType: metric.navigationType,
url: location.href,
referrer: document.referrer,
ua: navigator.userAgent,
connection: navigator.connection?.effectiveType,
deviceMemory: navigator.deviceMemory,
ts: Date.now(),
})

if (navigator.sendBeacon) {
navigator.sendBeacon('/api/rum', body)
} else {
fetch('/api/rum', { body, method: 'POST', keepalive: true })
}
}

onLCP(send)
onINP(send)
onCLS(send)
onFCP(send)
onTTFB(send)

3.2 sendBeacon

页面切换时 fetch 可能被中断,sendBeacon 异步保证发送。

3.3 Resource Timing

new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.duration > 1000) {
sendSlowResource({
name: entry.name,
type: entry.initiatorType,
size: entry.transferSize,
duration: entry.duration,
})
}
}
}).observe({ type: 'resource', buffered: true })

3.4 长任务

new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
sendLongTask({
duration: entry.duration,
startTime: entry.startTime,
})
}
}).observe({ type: 'longtask', buffered: true })

4. 采样

100% 上报数据量爆炸。常见策略:

  • 全采 Core Web Vitals(每页一次)
  • 10% 采资源加载
  • 1% 采详细 timing
  • 错误 100% 采
const SAMPLE_RATE = 0.1
if (Math.random() < SAMPLE_RATE) {
reportDetailedTiming()
}

按用户分组:

const userId = getUserId()
const sample = parseInt(userId.slice(-2), 16) / 255 < 0.1
// 同一用户始终采样或始终不采

5. 维度分组

不能只看平均,要分维度:

  • 页面:首页 vs 详情 vs 搜索
  • 设备:移动 vs 桌面
  • 网络:4g / 3g / wifi
  • 地区:国内 vs 海外
  • 用户类型:新 vs 老
  • 版本:v1.0 vs v1.1
  • 浏览器:Chrome / Safari / 微信内置

按维度看 P50 / P75 / P95 / P99,长尾用户也要照顾。

6. 后端接收

// Express
app.post('/api/rum', express.json({ limit: '10kb' }), (req, res) => {
const data = req.body
// 异步写 Kafka / 直接写 Prometheus / 转发 Loki
metricsQueue.send(data)
res.status(204).end()
})

或直接写时序数据库(InfluxDB / Prometheus pushgateway)。

7. 可视化

Grafana 看板:

  • LCP / INP / CLS 趋势(P75)
  • 按页面 / 设备 / 地区拆分
  • 与发版关联(看版本前后变化)
  • 错误率叠加

8. SaaS 方案

工具特点
Sentry Performance错误 + 性能一站式
Datadog RUM全面,贵
New Relic Browser老牌
Cloudflare Web Analytics免费简洁
Vercel AnalyticsVercel 用户友好
阿里 ARMS / 字节 Slardar国内

9. 实战:发现并解决慢页面

1. RUM 看板发现首页 P75 LCP 4s(差)
2. 拆分发现移动端 + 4G 用户最慢
3. Resource Timing:hero 图 800ms
4. 优化:WebP + responsive + preload
5. 部署后 RUM 数据 P75 LCP 降到 2s

10. 隐私合规

  • 不采集 PII(手机号、身份证)
  • IP 脱敏
  • 遵守 GDPR / CCPA(用户同意 / 不追踪选项)
  • Cookie 同意横幅

11. 常见反模式

  • 只看 P50:长尾用户看不见
  • lab 漂亮但 RUM 差:现实和实验环境差距大
  • 不分维度:移动端慢被桌面平均
  • 采样率 100%:数据量爆 / 后端打挂
  • 没有发版关联:上线后变慢不知是哪个版本
  • 上报阻塞主线程:用 sendBeacon 异步
  • 不限制后端接口请求量:被恶意刷
  • 采集 PII:合规风险

12. 延伸阅读