引言
线上质量是衡量研发团队实力的关键指标,也是研发人员日常关注的重点。在研发流程中,我们构建了技术方案评审、Code Review、UI 自动化测试及测试准出等多重保障体系,力求筑牢上线质量防线。即便如此,线上问题仍难以杜绝,一旦出现就会影响用户体验与业务形象。所以,引入高效的监控告警机制至关重要。它就像 “线上哨兵”,能及时察觉问题,助力快速修复或回滚,减少问题处理时长与损失。
告警现状
在前端工程化方案中,我们已经集成了 Slardar(类似 Sentry)进行监控上报,并配置了一些基础的告警规则,但是由于下列问题,导致告警接入实际上“形同虚设”,并没有发挥真正的作用:
- 告警数量多且噪音大:日均告警 1000+ ,其中 80% 以上是接口请求报错;
- 监控告警配置分散,前端人力难以有效覆盖: 有 40+ 监控,人均 3 个;
- 涉及多端、多业务场景、形态,规则差异大: 涉 3 个端(PC、H5、Lynx)、6 大核心业务(业务中台、Tiktok Ads Manager、Tiktok Business Center、TikTok Shop 等),2 种业务形态(ToB、ToC),不同场景的告警降噪规则差异大,很难在告警效性与漏放率之间找到平衡
- 缺少质量运营机制: 前端监控告警处于前端没人看,QA 不统计,前端相关线上问题基本靠用户反馈
解决思路
-
聚焦前端报错,对报警进行分级:
Slardar 会自动收集代码运行过程中产生的所有错误信息,其中 80% 以上是接口请求报错(最大噪音)。这和服务端已有的监控告警重合,通常不需要前端跟进,所以前端告警需要聚焦前端自身。
我们将告警配置分为确定性告警和非确定性报警两类。其中,确定性告警表示错误一旦触发则系统一定出现问题,包括:JS Runtime Error、白屏、接口 404/502 等;非确定性报警表示需要结合业务现状设置初始阙值,达到报警阙值后介入处理,如: PV、UV波动、唤起率、性能等,这类告警需要在过程中通过人工打标和 AI 学习不断调优阙值和规则,来提升不确定性中的确定性。
-
告警收敛, 将现有的 40+ 的告警配置,按照业务形态(ToB/ToB)收敛到 2 个,由不同小组负责跟进;
-
质量共建共赢,建立有效运营机制,沉淀高质规则: 前端回复及跟进问题,QA 进行核心指标统计、披露,双方定期共同对告警规则进行 Reivew(打标)和迭代,提升告警有效性,保障机制可长期运转。通过长期的运营也能沉淀不同的业务规则,来反哺业务,最终实现根据业务类型做规则自动推荐。
治理目标
告警治理的终极目标是提升线上问题召回率,实施过程也尤为重要,需要确保较高的回复率和较低的回复时长,来避免问题的漏放。我们期望短期内能将告警回复率提升到 90% 以上,并在完成初期探索后将告警回复率提升到 100%; P50 告警回复时长能在半小时内。
治理方案
异常检测原理
在字节前端监控实践一文中已经有 Slardar 内部实现比较详细的论述,下面主要介绍下白屏和页面卡死的检测原理:
白屏检测
白屏检测主要通过判页面加载完成后,根节点下是否有足够层级的元素可见,来判断页面是否白屏。具体检测流程可以参考下图:
-
在页面 load 完成之后等待一个
requestIdleCallback和requestAnimationFrame,然后开始监听变更,变更包括 DOM 变更、请求发送、资源加载、longtask 等 -
在每次变更后会查看目前是否有等待中的 打分任务。如果没有,会异步调度一次 打分任务。如果有,则取消当前等待中的打分任务,再异步调度一次新的打分任务
2.1 当打分的阈值大于等于设置的阈值时,则被认为是非白屏,继续等待下一次打分任务; 2.2 当打分的阈值小于设置的阈值时,则被认为是可能的白屏, 调度一次回测任务;
-
开始回测任务
3.1 如果在回测时间内没有其他用户交互类型的事件上报则被认为是回测通过,开始进行可选的截屏任务;
3.2 否则被认为是回测不通过,调度一次新的打分任务 -
开始可选的截屏任务
4.1 如果配置了不允许截屏,则会跳过截屏任务;
4.2 如果没有配置不允许截屏,则会去加载html2canvas的脚本,加载完成后开始截屏。若页面关闭时还没有截屏,则会立即结束截屏,开始上报数据。 -
开始上报数据,将采集到的 DOM 打分、DOM 快照、截屏等一系列数据进行包装,上报一条白屏事件。
-
在触发白屏至上报白屏的期间内,会继续进行打分任务 。如果打分的阈值大于等于设置的阈值,则会取消此次白屏的上报。
通常来说,如果事件处理函数、以及各种 hooks 中等异步代码中出现错误,仅会影响业务逻辑,如:表单联动,数据处理等;仅当组件渲染过程中错时才会导致页面白屏。通过 ErrorBoundary 进行上报会更加准确。
页面卡顿检测
通常来说我们认为某一帧渲染时长超过 1000/60 ms 时(按 1s 60 帧来算),即会导致页面卡顿。浏览器会在两次渲染任务的空隙之间调用 requestIdleCallback,通过这个 API,我们可以获取到每两帧渲染之间的时间间隔。但是如果遇到死循环等可能导致页面崩溃的场景,由于页面卡死,上述 API 并不会得到调用。所以我们可以结合 Service Worker 来实现。总体流程示意如下图:
错误标准化上报
为了按照预期的设想进行告警治理,我们需要对现有的上报内容进行一些标准化处理:
- 由于浏览器跨域的限制,非同域下的脚本执行抛错,捕获异常的时候,不能拿到详细的异常信息,只能拿到类似
Script error 0.这类信息。需要对所有的 scrips 添加 crossorigin="anonymous" 属性。 - 补全白屏和 React ErrorBoundary 等上报配置;
- 规范接口请求错误的上报, 分接口状态异常(HTTP Status 非 200)和普通的 RESTful 异常状态
告警规则配置
规则分类
| 告警分级 | 确定性告警 | 规则配置(示例) | 非确定性告警 | 配置规则(示例) | |
|---|---|---|---|---|---|
| 细分场景 | 页面白屏 | 新增错误类型 | |||
| JS Runtime Error | name include RangeError, TypeError, EvalError, SyntaxError, URIError, AggregateError, InternalError, ReferenceErrorError | PV、UV波动(to C) | |||
| 请求成功数跌 0 | SDK唤起率(to C) | ||||
| 接口404/超时 (to B) | code: (404) | (502) | 接口404 (to C) | code: not_200 | |
| 请求成功率(to C) | |||||
| 静态资源错误告警 | 数量 > xx 之后上报 (to c) | ||||
| 页面卡死 | 心跳检测 |
规则配置
由于前端项目数量较多,独立维护每个项目的告警规则配置需要耗费较大的精力,因此在告警工作台中增加告警配置功能,通过告警工作台实现多项目多规则的一键创建和更新。
质量运营
数据披露
为了避免一锤子买卖,我们需要将前端告警纳入 QA 的质量运行中,定期向业务泳道同步告警回复率、告警回复时长和线上问题召回率等各项指标。
规则运营
目前规则的定义主要通过分析现有的异常信息而来,在实际的运行过程中,可能需要结合实际情况来重新审视目前的规则定义是否合理或者完善,以不断的进行调整具体的规则内容和阈值。
- 有效性分析
- 规则调整
| 规则名称 | 规则配置 | 阙值调整 | 召回率 | 标签设置 | 是否下线 |
|---|---|---|---|---|---|
总结和展望
经过一个季度多的试运营,告警量由原先的 1000+ 降低到 10 以内,同时告警回复率也提升到 80% 以上,前端相关的线上问题召回率也从 0 提升到了 60%+。当然目前告警规则的配置和告警通知的回复主要都是通过人工来操作,未来需要进一步加强 AI 能力的建设,实现更加智能的降噪配置和自动归因。