本系列围绕Web端实时异常分析监控系统展开,从业务痛点、整体架构、客户端SDK采集、日志缓存同步策略、后端分析引擎、分级告警体系到业务闭环,逐层拆解一套完整自研监控系统的设计思路。本文是系列第一篇,主要梳理线上Web异常排查的行业痛点,对比现有解决方案的不足,介绍整套系统分层架构与核心能力边界。后续文章会针对各个模块展开工程层面的深度分析。
1. 前言
随着前后端分离模式大规模普及,Vue、React等SPA单页应用成为Web业务的主流技术选型。业务迭代速度越来越快,页面逻辑、接口调用链路日趋复杂,线上环境出现JavaScript报错、页面加载卡顿、接口异常失败的概率也随之提升。
在实际生产工作中,很多团队发现线上问题的方式十分被动:要么是用户过来反馈页面打不开、按钮没有反应;要么是后端查看服务端日志,发现接口大量报错。当开发拿到问题反馈的时候,异常已经对一部分真实用户产生了业务影响。
线上环境浏览器版本繁多、操作系统五花八门、用户网络环境参差不齐。很多BUG只在特定用户环境下复现,本地开发环境很难复现用户侧的真实问题。为了复现一个偶现的前端异常,开发人员往往需要反复和用户沟通,收集浏览器版本、操作步骤、复现时机,整个排查流程耗时久,人力成本很高。
市面上已经存在不少成熟的开源以及商业监控产品,很多团队会直接引入Sentry、Fundebug这类工具解决前端报错采集问题。但在私有化部署、自定义告警基线、异常责任人自动分派、性能指标联合分析等场景下,直接使用现成工具会存在一定的约束。
基于这样的业务背景,我们需要一套兼顾异常捕获、本地缓存、实时上报、多维度分析、分级告警、问题闭环的Web实时异常分析监控系统,主动感知线上各类异常,缩短问题发现与定位时间,降低异常带给业务与用户的损失。
重要说明:不存在可以捕获100%全部Web异常的监控系统。浏览器安全策略、跨域限制、网络中断、脚本加载失败等客观因素,都会造成部分异常无法被采集。本套方案核心目标是提升异常发现效率,缩短故障响应周期,而不是做到全量无遗漏的捕获。
2. 传统模式排查线上Web异常的痛点
传统的线上问题处理流程,大多遵循:用户反馈/后端日志发现问题 → 运维反馈开发人员 → 开发尝试复现问题 → 定位根因 → 修改代码 → 测试回归 → 版本发布。这套流程在业务规模小的时候尚且可以接受,当面向大量真实用户时,会暴露出多处短板。
2.1 问题发现严重滞后
异常已经真实发生、已经影响到部分用户之后,才能够被业务方或者用户感知。很多JS脚本错误不会直接导致页面崩溃,只是造成部分交互失效,用户不一定会主动反馈。这类隐性问题会长期潜伏在线上环境,持续影响用户体验。
2.2 问题复现难度高
前端异常高度依赖运行环境。同样一段业务代码,在Chrome新版本运行正常,在低版本浏览器、特定操作系统下就会触发报错。开发本地很难搭建出和用户完全一致的软硬件环境。缺少用户侧的报错堆栈、性能指标、浏览器环境信息,定位问题犹如盲人摸象。
2.3 报错与性能数据割裂
很多团队把JS报错监控、接口监控、页面性能监控拆分成多套独立工具。错误日志存放在A平台,接口指标存放在B平台,页面性能数据存放在另外一套系统。当出现故障时,开发人员需要切换多个平台交叉核对数据,无法在一个体系内完成报错、页面渲染耗时、接口成功率的联合分析。
2.4 告警规则固化,缺少灵活的自定义能力
通用监控工具内置的告警阈值大多是固定模板。不同业务系统容忍度完全不一样:后台管理系统可以接受接口最大响应时间5秒,面向C端用户的页面可能超过2秒就属于严重故障。通用工具想要深度定制报警基线、响应SLA、通知对象,往往会受限于产品功能或者付费版本。
2.5 缺少完整问题闭环
仅仅完成异常采集、消息推送不等于问题解决。告警消息发出之后,谁负责处理、处理进度、问题是否修复,缺少系统层面的流程跟踪。同一个异常反复告警,修复之后依然持续推送消息,很容易产生告警风暴,开发慢慢对告警消息麻木,真正严重故障也会被忽略。
3. 现有主流监控方案能力对比
市面上主流的前端监控方案分为两大类:开源自建方案、SaaS商业服务。每一类都有自己的适用场景与局限性。
| 方案类型 | 代表产品 | 优势 | 存在局限 |
|---|---|---|---|
| 开源方案 | Sentry | 开源可私有化,专注JS错误堆栈解析,社区生态成熟 | 性能指标、接口统计能力较弱;自定义告警基线、自动分派责任人需要大量二次开发;存储大规模日志时运维成本高 |
| 商业SaaS | Fundebug | 开箱即用,报错+性能指标一站式采集,无需运维 | 数据存放在服务商,私有化部署成本高;基线、告警流程定制化能力有限,受产品迭代约束 |
可以看到,直接复用现有方案,很难同时满足私有化部署、灵活告警基线、异常自动分派、报错‑性能‑接口一体化分析的全部诉求,因此就有了自研一套Web实时异常分析监控系统的设计出发点。
4. 整套系统整体分层架构
整套系统整体分为四大层级:客户端应用层、业务分析服务层、数据存储层、服务运行环境。客户端负责异常捕获、本地缓存、日志上报;业务分析服务层完成日志接收、异常分析、告警推送、任务闭环;存储层负责海量监控日志持久化;Node.js作为底层运行环境支撑整个服务。
#mermaid-svg-a1UQKmd9NIJSAVNT{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-a1UQKmd9NIJSAVNT .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-a1UQKmd9NIJSAVNT .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-a1UQKmd9NIJSAVNT .error-icon{fill:#552222;}#mermaid-svg-a1UQKmd9NIJSAVNT .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-a1UQKmd9NIJSAVNT .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-a1UQKmd9NIJSAVNT .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-a1UQKmd9NIJSAVNT .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-a1UQKmd9NIJSAVNT .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-a1UQKmd9NIJSAVNT .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-a1UQKmd9NIJSAVNT .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-a1UQKmd9NIJSAVNT .marker{fill:#333333;stroke:#333333;}#mermaid-svg-a1UQKmd9NIJSAVNT .marker.cross{stroke:#333333;}#mermaid-svg-a1UQKmd9NIJSAVNT svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-a1UQKmd9NIJSAVNT p{margin:0;}#mermaid-svg-a1UQKmd9NIJSAVNT .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-a1UQKmd9NIJSAVNT .cluster-label text{fill:#333;}#mermaid-svg-a1UQKmd9NIJSAVNT .cluster-label span{color:#333;}#mermaid-svg-a1UQKmd9NIJSAVNT .cluster-label span p{background-color:transparent;}#mermaid-svg-a1UQKmd9NIJSAVNT .label text,#mermaid-svg-a1UQKmd9NIJSAVNT span{fill:#333;color:#333;}#mermaid-svg-a1UQKmd9NIJSAVNT .node rect,#mermaid-svg-a1UQKmd9NIJSAVNT .node circle,#mermaid-svg-a1UQKmd9NIJSAVNT .node ellipse,#mermaid-svg-a1UQKmd9NIJSAVNT .node polygon,#mermaid-svg-a1UQKmd9NIJSAVNT .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-a1UQKmd9NIJSAVNT .rough-node .label text,#mermaid-svg-a1UQKmd9NIJSAVNT .node .label text,#mermaid-svg-a1UQKmd9NIJSAVNT .image-shape .label,#mermaid-svg-a1UQKmd9NIJSAVNT .icon-shape .label{text-anchor:middle;}#mermaid-svg-a1UQKmd9NIJSAVNT .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-a1UQKmd9NIJSAVNT .rough-node .label,#mermaid-svg-a1UQKmd9NIJSAVNT .node .label,#mermaid-svg-a1UQKmd9NIJSAVNT .image-shape .label,#mermaid-svg-a1UQKmd9NIJSAVNT .icon-shape .label{text-align:center;}#mermaid-svg-a1UQKmd9NIJSAVNT .node.clickable{cursor:pointer;}#mermaid-svg-a1UQKmd9NIJSAVNT .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-a1UQKmd9NIJSAVNT .arrowheadPath{fill:#333333;}#mermaid-svg-a1UQKmd9NIJSAVNT .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-a1UQKmd9NIJSAVNT .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-a1UQKmd9NIJSAVNT .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-a1UQKmd9NIJSAVNT .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-a1UQKmd9NIJSAVNT .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-a1UQKmd9NIJSAVNT .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-a1UQKmd9NIJSAVNT .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-a1UQKmd9NIJSAVNT .cluster text{fill:#333;}#mermaid-svg-a1UQKmd9NIJSAVNT .cluster span{color:#333;}#mermaid-svg-a1UQKmd9NIJSAVNT div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-a1UQKmd9NIJSAVNT .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-a1UQKmd9NIJSAVNT rect.text{fill:none;stroke-width:0;}#mermaid-svg-a1UQKmd9NIJSAVNT .icon-shape,#mermaid-svg-a1UQKmd9NIJSAVNT .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-a1UQKmd9NIJSAVNT .icon-shape p,#mermaid-svg-a1UQKmd9NIJSAVNT .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-a1UQKmd9NIJSAVNT .icon-shape .label rect,#mermaid-svg-a1UQKmd9NIJSAVNT .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-a1UQKmd9NIJSAVNT .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-a1UQKmd9NIJSAVNT .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-a1UQKmd9NIJSAVNT :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 运行环境
数据存储层
业务分析服务层
客户端应用层
异常处理闭环模块
异常报警模块
异常分析模块
IndexedDB本地存储
Web业务应用
JS Error捕获模块
页面性能捕获模块
API异常捕获模块
日志缓存区
日志同步区
HTTP / WebSocket上报通道
日志接收服务
JS Error异常分析
页面性能分析
API接口异常分析
异常数据可视化
责任人关联
多渠道消息推送
任务提醒管理
原始日志查询
LevelDB KV数据库
Node.js运行时
4.1 客户端应用层
客户端以 SDK 的形式接入业务 Web 应用,提供两种接入方式:npm 包引入、script 标签直接引入,尽可能降低业务的改造成本。
主要承担三类核心工作:
- 捕获 JavaScript 脚本错误、页面性能指标、API 接口调用异常;
- 使用 IndexedDB 实现浏览器端本地日志双分区缓存,避免大量异常瞬间爆发造成网络请求阻塞业务页面,同时解决断网场景下日志丢失的问题;
- 通过 WebSocket 实时上报,HTTP 作为降级兜底,把缓存的异常日志上报到后端分析服务。
设计关键点:SDK 需要做到低入侵,业务侧少量配置即可完成接入,不可以大规模侵入原有业务代码逻辑。
4.2 业务分析服务层
业务分析服务层是整套系统的核心大脑,接收客户端上报过来的全部原始日志,完成一系列业务逻辑处理。
- 异常分析模块:对 JS 错误、页面性能、接口异常做统计归类,识别严重故障、兼容性类问题,结合 source‑map 完成压缩代码堆栈还原;
- 异常报警模块:根据预设基线判断是否触发告警,匹配对应责任人,支持企业微信、短信多渠道推送告警信息;
- 异常处理闭环模块:提供任务管理、日志查询,记录异常处理状态,实现从发现异常到问题修复的完整业务闭环;
- 可视化模块:将统计指标通过图表进行展示,支持数据下钻,直观反映线上 Web 应用整体运行健康度。
4.3 数据存储层
监控系统会产生海量时序日志数据,本方案选用 LevelDB 高性能 KV 数据库作为存储。面对亿级日志数据写入读取场景,KV 数据库对比传统关系型数据库,拥有更好的读写性能,适配监控日志这种写入量大、查询以 key 为主的数据特征。
4.4 运行环境
整套后端服务基于 Node.js 环境运行,依托 Node 异步 IO 能力,处理大量客户端并发上报请求。
5. 系统核心能力总览
这套自研 Web 实时异常分析监控系统,完整能力可以归纳为下面几点:
- 多维度异常捕获:客户端 SDK 统一采集 JS 脚本错误、页面全链路性能指标、API 接口成功率与耗时指标,同时采集浏览器、操作系统、网络环境、访问 URL 等上下文信息;
- 浏览器本地缓存机制:借助 IndexedDB 做日志缓存区、同步区双分区,网络不佳时日志本地暂存,网络恢复之后再完成上报,降低日志丢失概率;
- 双通道上报:优先使用 WebSocket 做实时日志同步,网络环境不支持 WebSocket 的时候自动降级为 HTTP 上报;
- 多维度异常分析:统计错误发生频次、受影响用户规模,自动识别浏览器、操作系统兼容性 BUG;借助 source‑map 把压缩混淆后的错误堆栈还原为业务源码位置;
- 性能与接口统计:统计白屏时间、DNS、TCP、DOM 解析等关键性能指标;统计接口调用成功率、平均耗时,识别慢接口;
- 自定义分级告警:支持配置多等级告警基线,不同类型异常可以独立配置阈值,支持短信、企业微信多渠道推送告警消息;
- 异常处理闭环:告警触发之后生成处理任务,记录处理状态,修复完成之后解除告警,形成完整业务闭环;
- 可视化大盘:以图表形式展示线上整体异常、性能大盘,支持指标下钻查看原始异常日志。
6. 方案适用边界
任何技术方案都有自己的适用边界,这套监控系统也不例外,在落地之前要有清晰认知。
- 本方案面向 B 端、中大型 Web 业务系统,适合有私有化部署需求,需要深度定制告警、分析规则的团队;小型项目直接选用成熟 SaaS 服务会更节约人力;
- 受浏览器安全策略限制,跨域脚本异常、隐私模式下部分 API 不可用、页面彻底崩溃 SDK 脚本本身加载失败,这些场景会出现日志无法采集的情况;
- LevelDB 是本地 KV 存储,大规模集群部署场景需要额外做适配改造,原生更适合单机或者小规模部署;
- 本系列文章只讲解设计思路与工程方案,不会提供完整可直接复制部署的生产源码,仅供技术学习参考。
7. 本系列后续内容预告
- 第二篇:自研前端监控 SDK 设计:JS 错误、页面性能、API 接口三类异常如何完整采集;
- 第三篇:前端海量异常日志上报优化:IndexedDB 做本地缓存,解决上报阻塞、丢日志问题;
- 第四篇:线上 JS 报错如何快速定位源码位置?异常分析引擎、Source‑Map 反解与问题归类实现思路;
- 第五篇:Web 监控系统:页面性能、API 接口指标统计分析,可视化大盘设计思路;
- 第六篇:Web 监控告警不要乱轰炸:自定义基线、三级分级报警、多渠道通知体系设计方案;
- 第七篇【系列收官】:Web 实时异常监控系统:异常闭环流程、工程取舍,与 Sentry 方案横向对比总结。
本文为系列第一篇,介绍线上 Web 异常排查痛点以及整套监控系统的整体架构。下一篇我们将深入客户端 SDK,讲解三类核心异常的采集原理与工程难点。
版权声明:本文为技术思路探讨,相关方案仅做学习交流,请勿直接复制用于生产环境。