Skip to content

Latest commit

 

History

History
136 lines (67 loc) · 12.4 KB

Monitor.md

File metadata and controls

136 lines (67 loc) · 12.4 KB

监控的分类

  • 根据监控的手段
    • 被动监控:window.onerror 被动监听
    • 主动监控:try catch 主动上报
  • 根据监控的对象
    • 体验监控
    • js 报错监控
    • 供应链监控

监控能解决什么问题

异常可分为技术异常和逻辑异常。技术异常是指因为 js 报错、桥调用失败、网络链路问题等技术原因导致的诸如按钮点不动、页面白屏等功能性故障;逻辑异常是指一切技术功能正常的前提下,出现了不符合逻辑或预期的结果,也就是业务逻辑实现的问题,例如明明输入了手机号,却提示手机号不能为空。能够被监控的异常通常是技术异常,而逻辑异常一般很难靠被动监控发现,很大程度上只能靠人工深入到业务逻辑中,通过主动监控解决一部分问题。

监控与故障处理

线上故障处理可划分为五个环节:捕获、感知、定位、修复、总结。监控主要涵盖前三个环节。捕获的关键在于覆盖面,感知的关键在于报警,定位的关键在于日志信息的收集。

日志系统应该满足三个基本要求:

  • 全面(当你需要排查问题时,信息越充分越好)
  • 及时(用户报错,能够立即查到刚才发生了什么)
  • 聚合(能够按各种维度,搜索到需要的信息。并且能够可视化呈现多种维度的信息)

体验监控

体验分为性能体验、交互体验、视觉体验。

1、性能体验

性能体验通常就是指加载时长。计算加载时长的方法有很多,比如手动埋点计算时差、上报 DOMContentLoaded 和 load 事件的时间等。目前最正统的方式是用 performance API,不仅可以拿到各个加载环节的时间,还可以通过 performance.getEntries() 拿到所有资源的加载瀑布流。所谓慢会话追踪就是靠这个方法,当资源加载时长超过阈值,直接上报整个瀑布流数据,从而方便监控平台排查问题。

Google 提出了一套用户视角下的性能评价指标,将性能体验细分为四个阶段:

  • 首次渲染绘制的时间(First Paint / First Contentful Paint)
  • 核心内容呈现的时间(First Meaningful Paint)
  • 可交互的时间(Time to Interactive)
  • 后续使用过程中的交互性能(Long Task)

PerformanceObserver 可用于监控第一阶段的两个指标(FP、FCP),其它阶段目前需要靠开发者手动实现,尤其是 FMP 和 TTI 都是很难标准化定义的指标,需要业务方自己判断。Long Tasks API 用于监测重 js 运算的场景,目前已经作为草案提交,计划集成到 PerformanceObserver 中。

性能体验中一个比较独特的问题是白屏,也就是用户长时间看不到任何内容。导致白屏的原因有很多,比如 html 文件加载时间过长、某个关键资源加载受阻导致 DOM 解析过程 block、js 报错、接口超时、资源被劫持等。如果是 html 文件加载延迟导致的白屏,单靠前端是无法监控的,只能借助容器的能力,比如监控资源是否被劫持的一种思路:由 Native 实现 route-trace,检验 trace 中每个 IP 是否都在内部 IP 库中,如果查到某 IP 不存在,则判断为网络链路被劫持。

如果是 html 成功加载后出现白屏,前端怎么知道页面白屏了呢?一种间接的思路是监测 DOM 节点增量变化(MutationObserver),如果长时间 DOM 节点数没有变化,可能意味着页面没有内容呈现。

不过这个方案有个问题:有 DOM 节点也不一定意味着页面有内容呈现。白屏 === 没有像素渲染,所以最直接的方案应该是监测像素绘制到屏幕的时间。有两个 API 可以做到这一点:FP 和 FCP。FP 可以近似理解为第一个像素渲染出来的时间,这个指标确实可以准确的代表白屏时间,但实际意义可能不大,比如页面设置了背景色为黑色,但是没有内容渲染,这时候黑屏和白屏其实没有区别。因此更好的指标是 FCP:第一个内容元素渲染的时间,内容元素包括:文本、图片(含背景图)、有颜色的 canvas 和 svg。

除了事后监控,在事前也可以做监控,例如每次部署构建时,检测代码体积变化,如果某个 js 文件大小相比上次部署有大幅变动,就给出报警提示。

2、交互体验

交互体验的衡量指标包括 FPS、点击延迟等。FPS(frame per second,帧率)的最佳值为 50 ~ 60,低于 24 可认为是不良指标,低于 12 则会产生明显可感知的卡顿。查看 FPS 最简单的办法有两个,一是用 stats.js ,二是在 chrome devtools 中通过 command + shift + p 调出命令窗口,输入 fps 即可调出帧率面板。

stats.js 计算帧率的原理并不复杂,就是无限循环的执行 requestAnimationFrame,然后计算每一帧的时间。如果超过 50ms(帧率低于 20)就意味着性能不太好。这种方案显然不应该放在线上环境运行,因为无限循环本身就会影响性能,并且消耗资源(耗电)。

点击延迟既可以算作性能体验,也可以算作交互体验。主要针对异步加载的场景,点击一个按钮,到异步组件展示出来会有一定延迟,尤其是单页应用,在监控时需要考虑覆盖此场景。

3、视觉体验

视觉体验主要针对因 CSS 兼容问题、文件样式加载失败等导致的样式渲染错误

一般情况下体验监控就是性能监控,交互和视觉的监控收益很低,一般来说更适合在事前阶段处理。

js 报错监控

js 报错监控有两个关键:一是有效,二是全面。

无效的报错会浪费开发的注意力,因此需要对报错信息进行过滤,提高报错的有效性。首先需要过滤无效访问,例如爬虫、单一 IP 的大量访问等非正常用户访问的情况;其次需要过滤无效报错,比如容器环境报错、浏览器插件报错等。有的国产浏览器可能会往页面注入一些广告脚本,这些外部代码导致的异常也应该过滤掉。

报错的目的是为了定位错误,因此应该尽可能全面的收集报错信息,包括资源 url、行列数、错误堆栈、容器、设备、网络环境、地理位置等。js 报错监控有两个难点,第一是我们不知道报错发生时,用户究竟陷入了什么困境;第二是我们不知道用户究竟是如何一步步陷入困境的。代码错误定位比较容易,靠行列数、堆栈、sourceMap 都行,难的是故障还原,仅靠监控有时很难定位与还原问题,因此需要结合用户行为日志和主动监控。

有时候即便记录了用户所有的点击行为,提供的信息也是有限的,因为复杂应用中存在各种状态和条件分支,所谓“千人千面”,不同用户接收的数据、所处的状态是不一样的。

如果说视图是数据结构的严格映射,那么从根本上讲,只有记录所有的数据变化,才能直接还原、回放与复现故障发生的整个流程。

供应链监控

什么是供应链监控呢?如果将 CDN、接口、容器、网络环境等都视为一种微服务,前端负责整合各类微服务形成最终产品,那么这些微服务就可以视为前端的供应链。

1、接口监控

接口监控的对象主要是网络错误率和业务错误率。

请求一个接口,有三种返回情况:网络异常、业务异常、业务正常。我们只要针对这三种情况上报信息即可统计出网络错误率和业务错误率。

网络错误比较好判断,http status 大于 400 即可认为是网络错误。问题是接口错误怎么界定呢,接口通常会返回一个状态码字段,并约定一个值表示正常,其它的值表示异常,如果我们将状态码不等于正常值的情况全部视为业务错误并上报,显然会使业务错误率过低,因为有些“异常”状态码其实是正常的,例如返回 { status: 999, message: "余票不足" },这显然不是错误。再比如 { status: 1000, message: "未登录" },这个算正常还是异常呢?所以这就涉及到状态码的设计问题,前后端应该约定一组状态码区段,例如 0 表示正常,正数表示“正常的异常”,负数表示异常,这样前端的上报逻辑就很明确了。

2、静态资源监控

静态资源监控的对象首先是加载时间和体积,这两个数据都可以通过 performance.getEntries() 方便的获得,对加载时间的监控除了体现网络性能之外,还可以监测网络异常,因为 cdn 并不是完全可靠的,很可能因为某个节点问题导致资源加载受阻,在用户端的表现就是长时间白屏。

另一个问题是,如何监控资源是否被劫持?所谓劫持就是指静态资源在网络传输过程中被注入了其它代码,导致页面被插播广告、跳转链接被篡改等,即便使用了 https 也不能完全防止这个问题。目前有一个 API 可用于监控资源是否被劫持:Subresource Integrity,它的原理很简单,就是在 script 或 link 标签上标志资源的 hash 值,浏览器请求到资源后会做一次 hash 校验,如果文件被篡改,就会触发 onerror。知乎小爝在这篇文章中提供了实践应用。

报警策略

软件 = 正常功能 + 已知 bug + 未知 bug。

未知 bug 总是存在,当未知 bug 发生时,工程师的感知来源通常有三个:监控系统反馈、内部自己人反馈(比如产品、运营或 QA)、用户反馈(通过客服)。通常来讲最好的是监控反馈,最糟的是用户反馈,因为这意味着产生了客诉,问题比较严重。最理想的情况是未知 bug 首次发生时就被感知到,随即被修复。这就涉及到报警问题,不能报警的监控系统是残疾的。

衡量报警表现的唯一指标就是准确率,误报太多,等于报警无效。决定报警准确率的主要是报警策略的设计,不同的业务有各自的流量特征,具体使用哪种策略需要根据业务特点定制。

1、常规的报警策略

绝对值报警。接口的成功率和 js 异常的个数,都属于绝对值,最简单的做法是:针对单个页面,在一定的连续的时间段内(比如 5 分钟),错误数量超过上限则报警。这种方案可能的问题是带来较多误报,比如某一时刻偶发的大量异常或网络抖动引起的报警。为了平滑包容单点异常情况,可以考虑取异常数据点的比例,也就是说连续的 10 个数据点,超过上限的数据点达到 n 个就报警。绝对值报警的一个问题是很难确定绝对值是多少才合理,常常只能预估一个值。随着访问量的增长,绝对值的设置可能需要人工调整。

相对值报警。相对值报警反映的是一段时间内的指标走势。如果指标陡增或陡降则报警。例如最近 3 分钟的三个数据,相对于前 10 分钟的十个数据的增长比例都超过了上限,则表明异常数据正在稳定持续的上升。除了同一时间段内的相对走势,还有时间段之间的相对走势。例如今天的走势曲线和昨天或者上周同一天的走势曲线对比,如果曲线拟合出现较大偏移,也可以说明存在异常需要报警。

2、特殊的报警策略

首次异常报警。如果某个异常在之前一段时间内(比如三天、一周)都没有出现过,就属于首次出现的异常,这意味着可能是最近某次上线或某个地方改动导致的问题,只要是首次出现的异常,就直接报警。

短时间内重复异常报警。如果在一定时间段内(比如 5 分钟),同一个 ip 产生的同一个错误超过上限,可能意味着用户在反复尝试,但一直因为报错而无法成功。

前端代码异常监控 by 微信 拉风

大前端时代前端监控的最佳实践 by 阿里 彭伟春

把前端监控做到极致 by 阿里 杨森

2017前端监控系统探索总结 from 美团

client-javascript-reporting-window-onerror