从零构建高可用异常监控系统:核心架构与实现指南

一、系统架构设计

异常监控系统需满足三大核心需求:实时性、可靠性和可观测性。系统采用分层架构设计:

  1. 数据采集层:捕获JS错误、资源加载失败、异步请求异常等
  2. 数据处理层:实现错误去重、数据缓存、录屏关联
  3. 数据上报层:支持多种上报策略,确保数据不丢失
  4. 可视化层:提供录屏回放和错误分析界面

核心数据结构示例:

  1. interface ErrorData {
  2. id: string;
  3. type: 'js' | 'resource' | 'async';
  4. message: string;
  5. stack?: string;
  6. timestamp: number;
  7. fingerprint: string; // 错误唯一标识
  8. sessionId: string; // 会话ID
  9. screenId?: string; // 关联录屏ID
  10. }
  11. class MonitorSystem {
  12. private errorQueue: ErrorData[] = [];
  13. private errorCache = new Set<string>();
  14. private screenRecorder: any; // 录屏实例
  15. private timer?: NodeJS.Timeout;
  16. private readonly MAX_QUEUE_SIZE = 100;
  17. private readonly REPORT_INTERVAL = 60000;
  18. }

二、全局错误监听实现

1. 错误类型分类处理

  • JS错误:通过window.addEventListener('error')捕获
  • 资源错误:监听window.addEventListener('error')target.src属性
  • 异步错误:重写Promise.prototype.then/catchXMLHttpRequest.send
  1. // 资源加载错误处理示例
  2. window.addEventListener('error', (event) => {
  3. if (event.target && (event.target as HTMLScriptElement).src) {
  4. const errorData = {
  5. type: 'resource',
  6. message: `Resource load failed: ${(event.target as HTMLScriptElement).src}`,
  7. timestamp: Date.now()
  8. };
  9. this.addErrorToQueue(errorData);
  10. }
  11. }, true); // 使用捕获阶段

2. 主动上报接口设计

提供灵活的上报接口,支持自定义错误数据:

  1. class MonitorSystem {
  2. public reportError(error: Partial<ErrorData>) {
  3. const fullError = {
  4. id: uuid(),
  5. type: 'custom',
  6. timestamp: Date.now(),
  7. ...error
  8. };
  9. this.addErrorToQueue(fullError);
  10. }
  11. }

三、数据持久化与恢复机制

1. 本地存储方案

采用三级存储策略:

  1. 内存队列:实时处理最新错误
  2. LocalStorage:持久化未上报数据
  3. IndexedDB:存储录屏数据(当数据量>5MB时)
  1. private loadFromStorage() {
  2. const savedErrors = localStorage.getItem('errorQueue');
  3. if (savedErrors) {
  4. const parsed = JSON.parse(savedErrors);
  5. this.errorQueue = parsed.filter(err => {
  6. const isValid = this.validateError(err);
  7. if (!isValid) this.errorCache.delete(err.fingerprint);
  8. return isValid;
  9. });
  10. }
  11. }

2. 智能合并策略

系统初始化时执行数据恢复流程:

  1. 从存储加载历史错误
  2. 检查错误指纹是否已存在
  3. 合并相同会话的连续错误
  4. 优先保留最新错误数据

四、错误去重与关联分析

1. 指纹生成算法

采用多重特征组合生成唯一标识:

  1. private generateFingerprint(error: ErrorData) {
  2. const { type, message, stack, sessionId } = error;
  3. return crypto.createHash('sha256')
  4. .update(`${type}|${message}|${stack?.substring(0, 200)}|${sessionId}`)
  5. .digest('hex');
  6. }

2. 录屏关联机制

通过rrweb实现行为录制:

  1. 错误发生时记录时间戳
  2. 在录屏数据中标记错误点
  3. 上报时关联最近的录屏片段
  1. private initScreenRecording() {
  2. this.screenRecorder = new rrweb.record({
  3. emit: (event) => {
  4. this.screenEvents.push(event);
  5. // 自动清理旧数据
  6. if (this.screenEvents.length > 1000) {
  7. this.screenEvents.shift();
  8. }
  9. }
  10. });
  11. }

五、智能上报策略

1. 三种上报方式对比

方式 适用场景 优缺点
Request 大数据量/需要响应 占用资源较多
Image 跨域环境 简单可靠,无法获取响应
Navigator 移动端/低性能设备 兼容性好,功能有限

2. 定时上报实现

  1. private startReportTimer() {
  2. if (this.timer) clearInterval(this.timer);
  3. this.timer = setInterval(() => {
  4. if (this.errorQueue.length === 0) return;
  5. const batch = this.errorQueue.splice(0, 20); // 批量上报
  6. this.sendBatch(batch).catch(err => {
  7. // 上报失败时恢复队列
  8. this.errorQueue.unshift(...batch);
  9. console.error('Report failed:', err);
  10. });
  11. }, this.REPORT_INTERVAL);
  12. }

六、生产环境优化建议

  1. 采样率控制:根据QPS动态调整监控比例
  2. 错误分级:区分致命错误和普通错误
  3. 隐私保护:敏感数据脱敏处理
  4. 性能监控:集成页面性能指标采集
  5. 告警集成:对接监控告警系统

七、扩展功能实现

1. 录屏回放组件

  1. <div id="player-container"></div>
  2. <script>
  3. function playbackError(screenId) {
  4. const events = getScreenEvents(screenId); // 从存储获取
  5. const player = new rrwebPlayer({
  6. target: document.getElementById('player-container'),
  7. data: { events }
  8. });
  9. player.play(findErrorTime(screenId)); // 定位到错误发生时刻
  10. }
  11. </script>

2. SPA路由监控

  1. private initPageHandler() {
  2. // 监听路由变化
  3. if (window.history.pushState) {
  4. const originalPush = history.pushState;
  5. history.pushState = (...args) => {
  6. originalPush.apply(history, args);
  7. this.handleRouteChange();
  8. };
  9. }
  10. }
  11. private handleRouteChange() {
  12. // 结束当前会话,创建新会话
  13. this.flushErrorQueue();
  14. this.sessionId = uuid();
  15. }

总结

构建异常监控系统需要综合考虑错误捕获、数据持久化、智能上报等多个环节。通过分层架构设计和模块化实现,可以创建出既稳定又灵活的监控解决方案。实际开发中建议:

  1. 先实现核心功能,再逐步扩展
  2. 重视数据安全和隐私保护
  3. 建立完善的测试用例覆盖各种错误场景
  4. 监控系统本身需要具备高可用性设计

完整实现代码可参考开源社区的异常监控项目,结合自身业务需求进行定制化开发。对于中大型项目,建议将监控系统与日志服务、对象存储等云服务集成,构建完整的可观测性体系。