前端稳定性:监控 SDK 与故障闭环
设计覆盖错误、性能、资源、请求和用户行为的前端监控 SDK,并处理采样、隐私、上报与定位。
前端稳定性:监控 SDK 与故障闭环
本文聚焦监控系统的设计边界、数据质量和故障闭环。
1. 监控的目标
监控不是把所有事件都发到服务器,而是让团队能回答三个问题:发生了什么、影响了谁、如何复现和修复。SDK 采集层应尽量轻量,服务端聚合和告警层负责分析;采集失败不能影响主业务。
建议按四类信号建模:
- 错误:运行时异常、未处理 Promise、资源加载失败、接口失败和框架错误。
- 性能:导航、资源、长任务、交互延迟、核心 Web Vitals(如 LCP、INP、CLS)。
- 请求:URL 模板、方法、状态、耗时、traceId 和取消/超时原因。
- 行为:页面访问、关键交互和用户操作路径;默认只记录必要的事件名称,不采集输入框原文。
2. 统一事件信封
所有信号使用统一字段,便于关联和采样:
type MonitorEvent = {
id: string
type: 'error' | 'performance' | 'request' | 'behavior'
occurredAt: number
sessionId: string
page: { url: string; route?: string }
release?: string
traceId?: string
payload: Record<string, unknown>
}
id 应在客户端生成并用于去重;release 用来匹配源码映射和部署版本。URL、错误消息和自定义属性在进入队列前就要脱敏,不能把清洗责任全部推给服务端。
3. 错误捕获边界
function installErrorCapture(report: (event: MonitorEvent) => void) {
window.addEventListener('error', (event) => {
const target = event.target
const isResource = target instanceof HTMLScriptElement ||
target instanceof HTMLLinkElement || target instanceof HTMLImageElement
report(isResource
? createEvent('error', { kind: 'resource', url: getSafeUrl(target) })
: createEvent('error', { kind: 'runtime', message: event.message, stack: event.error?.stack }))
}, true)
window.addEventListener('unhandledrejection', (event) => {
report(createEvent('error', {
kind: 'unhandledrejection',
reason: normalizeError(event.reason),
}))
})
}
框架错误边界负责捕获组件树中的渲染错误,但不能替代全局监听。跨域脚本常常只能得到“Script error.”;应通过正确的 CORS 响应和 crossorigin 配置改善堆栈,同时接受第三方脚本不可观测的边界。错误应按 fingerprint 聚合(类型、文件、行列、标准化消息),避免同一问题刷爆告警。
4. 性能与请求采集
使用 PerformanceObserver 观察导航、资源、长任务和布局偏移,优先在空闲时间汇总,而不是每条资源都立刻上报。首屏阶段可先缓存关键指标,页面隐藏或卸载时用 navigator.sendBeacon 尝试发送;Beacon 失败时可由服务端重试策略或下一次启动补偿,不能阻塞卸载。
请求拦截器应记录方法、脱敏后的 URL 模板、状态、耗时和 traceId,不记录完整请求体或 Authorization。对慢请求和错误请求提高采样率,对正常请求按会话或哈希稳定采样,避免同一用户的样本在页面间随机跳动。
5. 队列、上报与降级
采集 -> 脱敏/标准化 -> 采样 -> 内存队列 -> 批量压缩 -> Beacon/fetch 上报
| |
+-- 超限丢弃 +-- 失败退避/熔断
- 队列必须有事件条数和字节上限;超限时优先保留错误和关键性能事件。
- 上报接口使用独立域名或路径,并设置超时、重试上限和指数退避。
- 连续失败时熔断一段时间,避免网络异常放大请求压力。
- SDK 初始化失败、CSP 阻断或浏览器 API 缺失时静默降级,不抛出影响业务的异常。
- 采集 SDK 自身的错误要有内部计数器,但不能递归上报同一错误。
6. 隐私与合规
默认采用数据最小化:不采集输入框内容、Cookie、令牌、完整 IP 或未经必要性评估的设备指纹。对 URL 查询参数、错误消息和自定义上下文做字段级脱敏;提供采集开关、用户同意状态、数据保留期限和删除机制。第三方脚本、跨境传输和小程序平台还需要遵守各自的权限与隐私要求。
7. Source Map 与定位
生产错误定位依赖“发布版本 + 构建产物 + 对应 Source Map”三者一致。Source Map 不应公开暴露源码;可以上传到受控的错误平台,客户端只携带 release 和文件名。部署时生成校验清单,防止旧版本错误匹配到新映射。错误详情应包含页面路由、浏览器版本、最近的请求 traceId 和用户可复现步骤,但仍要经过脱敏。
8. 告警和故障闭环
告警按影响面和趋势分级,而不是每个事件一条告警。常见维度包括错误率、受影响会话数、P75/P95 性能、资源失败率和接口超时率。告警应链接到聚合后的样本、发布版本和回滚入口;故障结束后记录根因、修复提交、回归测试和监控规则调整,形成闭环。
9. 大促高可用保障
9.1 稳定性是分层体系
稳定性不是单一的监控项目,可以用一组由底到顶的能力检查系统:
Monitoring
-> Incident Response
-> Postmortem / Root Cause Analysis
-> Testing and Release Procedures
-> Capacity Planning
-> Product
-> Development
监控让团队知道异常已经发生或即将发生,应急响应让问题被有序处理,复盘把一次故障转化为改进项,测试和发布管控限制变更风险,容量规划应对流量和业务规模变化,研发与产品设计则从源头降低系统复杂度。这个层级适合作为稳定性检查清单,不应被理解为只要接入前端 SDK 就能获得高可用。
9.2 先梳理入口、依赖和业务变量
大促保障通常在有限周期内完成,应该先找关键链路和薄弱节点,再决定投入点。入口盘点可按优先级覆盖:
- 核心重保入口:对服务等级、准确性和响应时间有明确承诺。
- 资损入口:故障可能直接影响公司或客户资金。
- 大流量入口:按 TPS/QPS 排名前列,即使业务有损较小,也可能把整体容量打满。
沿入口追踪 HTTP、RPC、消息和外部存储等节点,并分别判断:节点不可用是否会中断业务、返回错误或显著拖慢系统;日常是否经常超时或资源不足;最近是否有大版本改造、首次参加大促、历史高等级故障或资损风险。强依赖必须有明确的替代或切换策略,弱依赖则应提前设计降级边界。
容量模型不能只看本服务机器数,还要把上游流量、下游容量、业务量倍数、峰值日期和场景流量分配放在同一张链路图中,并用压测或历史数据验证峰值余量。特殊玩法和应急策略也应在活动前同步,否则技术预案无法正确评估影响。
9.3 监控和告警要覆盖三层信号
黑盒监控关注用户看到的结果,白盒监控关注系统内部状态和原因。大促梳理时可从核心和资损链路出发,按三层建立监控模型:
- Biz:成功率、业务延时、关键状态和资损指标,最接近用户感受。
- Application:运行时、线程/进程、中间件和数据库等应用依赖。
- System:CPU、内存、网络、磁盘和机器水位等基础资源。
每层都可以用四个黄金信号归类:Latency、Errors、Traffic、Saturation。业务层异常优先触发告警,应用和系统层更多用于定位原因,只有高风险指标才需要实时通知。每条告警至少明确级别、触发阈值、持续时间、通知人、通知方式,以及是否关联故障升级、资损和应急预案。阈值不能过迟,也不能因过敏造成告警疲劳;必要时结合多个指标和业务波动曲线。
专项梳理的产出应可被执行和审计:监控点清单、告警模型、业务大盘、应用/系统大盘,以及每项指标对应的日志和预案链接。已有 SDK 的错误、请求、性能和行为事件可作为 Biz 层信号的采集来源,详见错误捕获边界和性能与请求采集。
9.4 把临场决策变成预案和作战手册
值班人员在高并发故障现场应该做选择题,而不是临时发明处理方案。预案按执行时机和影响对象可分为四类:
- 技术应急:节点不可用时的限流、降级、摘除或切换。
- 技术前置:峰值前提前熔断弱依赖、暂停冲突的离线任务、校验容量和开关。
- 业务应急:业务数据错误、玩法变更或需要业务确认的有损处理。
- 业务前置:配合活动节奏提前调整配置和服务策略。
每份预案都应写清执行/关闭时间、触发和恢复阈值、系统与业务影响、决策/执行/验证人员,以及开启和关闭的验证方式。把入口、流量分支、依赖强弱、资损评估和预案汇总成全链路作战地图,才能从一个告警反查受影响范围,并反向检查容量与预案是否完整。
作战手册按事前、事中、事后组织:事前检查权限、限流、开关、数据库和中间件容量以及监控有效性;事中提供预案、排查脚本、日志源、大盘、上下游分组、值班通讯录和问题记录;事后恢复限流/扩容设置并完成复盘。每项检查都要有执行人、检查方法和结果,避免只列链接不留证据。
9.5 演练和事故指挥
沙盘演练应使用历史真实故障作为输入,重点验证止血、分工和定位,而不是只检查文档是否存在。现场原则是先恢复服务,同时保留机器、日志和水位等证据;依据白盒指标缩小范围;明确职责,避免多人同时修改同一开关;无法技术恢复时及时转为业务影响和资损评估。
常见止血动作包括入口限流、弱依赖降级、摘除异常单点,以及单元切流或备份切换。事故管理至少需要四个角色:事故总控负责全局协调和未分配事务,处理团队负责具体修复,发言人向内外同步并维护状态文档,规划负责人负责轮班和职责交接。配套的作战室、实时事故文档和公开交接记录,能让长时间故障保持信息一致。
来源:大促搭投实践&高可用性保障(简化版).pdf 第 9-17 页。
10. 测试清单
- 模拟运行时错误、Promise 拒绝、资源失败、网络超时和 Beacon 不可用。
- 检查事件去重、采样稳定性、队列上限、重试退避和熔断。
- 验证脱敏规则不会泄露 URL 参数、表单值和认证信息。
- 在 SSR、Web Worker、旧浏览器和小程序适配层分别测试能力检测与降级。
- 使用构建版本 fixture 验证 Source Map 关联和 release 不匹配时的安全失败。