2021- 应用性能前端监控,字节跳动这些年经验都在这了
应用性能前端监控,字节跳动这些年经验都在这了
一、背景
字节跳动发展至今,线上已经有数量级庞大的
随着用户数量的不断增长,对于站点体验衡量的的需求也日益紧迫,用户会将产品和他们每天使用的体验最好的
性能是留住用户的关键。 大量的研究报告已经表明了性能和商业成绩的关系,糟糕的性能会让您的站点损失用户数、转化率和口碑。错误监控则能够让开发者第一时间发现并修复问题,单靠用户遇到问题并反馈是不现实的,当用户遇到白屏或者接口错误时,更多的人可能会重试几次、失去耐心然后直接关掉您的网站。
字节跳动开发团队根据内部数十款产品的体验监控需求,逐渐打磨出了一版性能监控平台。经过不断的锤炼和沉淀,正式在火山引擎上对外发布应用性能监控 全链路版。本文将会重点介绍它到底是一个怎样的监控平台,以及可以帮助企业解决哪些痛点。
二、产品简述
应用性能监控全链路版是字节跳动旗下的企业级技术服务平台,为企业提供针对应用服务的品质、性能以及自定义埋点的
基于海量数据的聚合分析,平台可帮助客户发现多类异常问题,并及时报警,做分配处理,同时平台提供了丰富的归因能力,包括且不限于异常分析、多维分析、自定义上报、单点日志查询等,结合灵活的报表能力可了解各类指标的趋势变化。更多功能介绍,详见各子监控服务的功能模块说明。
三、产品亮点
该部分仅以整个产品的视角说明了应用性能监控全链路版的亮点,更多技术亮点与优势,我们会在各功能模块中为您详细说明。
在接入
// npm install @apm-insight-web/rangers-site-sdk
// 在项目最开始的地方引入下面的代码
import vemars from '@apm-insight-web/rangers-site-sdk/private'
vemars('config', {
app_id: {{你的appid}},
serverDomain: {{私有化部署服务器地址}},
})
或者通过一段
<!-- 脚本 -->
<!-- 页面 <head> 标签顶部添加以下代码 -->
<script>
(function (i, s, o, g, r, a, m) {
i["RangerSiteSDKObject"] = r;
(i[r] =
i[r] ||
function () {
(i[r].q = i[r].q || []).push(arguments);
}),
(i[r].l = 1 * new Date());
(a = s.createElement(o)), (m = s.getElementsByTagName(o)[0]);
a.async = 1;
a.src = g;
a.crossOrigin = "anonymous";
m.parentNode.insertBefore(a, m);
i[r].globalPreCollectError = function () {
i[r]("precollect", "error", arguments);
};
if (typeof i.addEventListener === "function") {
i.addEventListener("error", i[r].globalPreCollectError, true);
i.addEventListener("unhandledrejection", i[r].globalPreCollectError);
}
if ("PerformanceLongTaskTiming" in i) {
var g = (i[r].lt = { e: [] });
g.o = new PerformanceObserver(function (l) {
g.e = g.e.concat(l.getEntries());
});
g.o.observe({ entryTypes: ["longtask"] });
}
})(window, document, "script", "{{你的CDN地址}}", "RangersSiteSDK");
</script>
<script>
window.RangersSiteSDK("config",{
app_id: {{你的app_id}},
serverDomain: {{私有化部署服务器地址}},
});
</script>
应用性能监控全链路版不仅帮助您无死角地发现各类异常问题,还提供了丰富的现场还原能力,包括且不限于堆栈回溯、用户交互还原等。
应用性能监控全链路版为您提供了采样配置,支持按功能模块设置采样、按用户设置采样,以帮助您节省事件量。
如此完善的性能监控平台,背后一定有一套成熟的方法论。从平台设计之初,我们就做好了详细的技术方案设计和衡量标准设计,接下来我会从更细节的角度来介绍这些设计,以及背后详细的原理。
四、怎样衡量Web 体验
4.1 站点体验
首先,从站点体验方面来讲,
基于长期以来的体验指标优化积累,最新的核心体验指标主要专注于加载、交互、视觉稳定,加载的速度决定用户是否可以尽早访问到视觉上的图像,可交互的速度则决定用户心理上是否可以尽快感觉页面上的元素可以操作,而视觉稳定性则负责衡量页面的视觉抖动对用户造成的负面影响。
综合下来就是下面的
Largest Contentful Paint (LCP)
最大内容绘制,是用来测量加载的性能。这个指标上报视口中可见的最大图像或文本块的渲染的时间点,为了提供良好的用户体验,
First Input Delay (FID)
第一次输入延迟,用于测量可交互性。
Cumulative Layout Shift (CLS)
累计布局位移,用于测量视觉稳定性。
4.2 错误监控
再从错误监控来讲,当页面达到数以亿计的访问量时,无论发布前单元测试、集成测试以及人工测试过了再多轮,都难以避免的会漏掉某些边缘操作路径的测试,甚至偶尔会出现难以复现的玄学故障。哪怕这些错误只有
这时候,完善的错误监控体系就派上很大的用场。
我们对
同时对于请求的监控,为了进一步保证用户在获取数据上的体验,我们还进一步的细化到了请求的成功率、慢查询相关的指标。
五、
有了这些衡量标准,我们来具体看看
5.1 需要采集什么指标?
RUM (Real User Monitoring) 指标,包括FP, TTI, FCP, FMP, FID, MPFID 。Navigation Timing 各阶段指标,包括 DNS, TCP, DOM 解析等阶段的指标。- JS Error,解析后可以细分为运行时异常、以及静态资源异常。
- 请求状态码,采集上报后,可以分析请求异常等信息。
5.2 如何采集这些指标?
以first-input
事件监听到 first-input
事件后,利用
// Create the Performance Observer instance.
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
const FID = entry.processingStart - entry.startTime;
console.log("FID:", FID);
}
});
// Start observing first-input entries.
observer.observe({
type: "first-input",
buffered: true,
});
PerformanceTiming
接口得到它们,以加载时间的计算为例:
function onLoad() {
var now = new Date().getTime();
var page_load_time = now - performance.timing.navigationStart;
console.log("User-perceived page loading time: " + page_load_time);
}
window.onerror
回调函数即可监听
window.onerror = function (message, source, lineno, colno, error) {
// 构造异常数据格式并上报
}
通过 unhandledrejection
事件监听
window.addEventListener("unhandledrejection", (event) => {
// 构造异常数据格式并上报
});
请求状态码,则可以通过覆写 window.fetch
和 XMLHttpRequest
对象来实现监听,以覆写 fetch
为例,以下是简化后的代码:
const _fetch = window.fetch;
window.fetch = (req: RequestInfo, options: RequestInit = {}) => {
// 省略一些逻辑……
return _fetch(req, options).then(
// 成功
(res) => {
// 上报成功请求信息
return res;
},
// 失败
(res) => {
// 上报失败请求信息
return Promise.reject(res);
}
);
};
六、服务端处理
服务端接收数据后,对数据进行实时纬度解析补充,堆栈反解析等清洗任务。根据不同平台产品功能,分门别类落地在不同类型的存储中:
-
数据收集层:数据收集层是无状态的
API 服务,逻辑较轻。只提供针对SDK 上报数据的鉴权校验, 拆包等工作, 然后写入消息队列Kafka 供数据清洗层消费 -
数据清洗层:数据清洗层是数据处理的逻辑中心。提供堆栈格式化,堆栈还原(
SourceMap 解析) , 纬度补充(IP -> 地理位置,User-Agent -> 设备信息)等处理工作。为平台的多维分析统计,数据下钻等提供数据支撑。 -
存储层:平台根据不同的功能需求, 选择不同类型的存储方案, 实现实时秒级响应的平台查询。
-
OLAP: 我们选择Clickhouse 作为我们数据分析的存储方案。Clickhouse 强大的性能和字节内部针对性的优化, 可以帮助我们实现每日千亿级别数据, 秒级查询的效果。- KV:字节内部自研高性能
KV 存储数据索引信息, 结合HDFS 存储详情。实现平台单点查询等详情追查功能。 - ES:对于一些自定义日志分析搜索场景,我们使用
Elastic Search 作为存储,实现比较灵活的日志搜索分析功能。
在报警功能上,我们通过实现抽象的报警查询引擎(底层可适配不同数据源
在
七、可视化平台展示
经过了上文所述的采集上报 —— 存储清洗 —— 统计分析等工作后,接下来就需要把这些数据交由用户来消费,可视化平台的功能也是至关重要的,接下来我将为您详细介绍平台中的各个功能。
7.1 性能分析
性能分析模块,分为页面加载和静态资源性能两个子模块。
页面加载监控是对用户会话过程中前端页面的性能监控。其中可查看的指标分类包括:真实用户性能指标和页面技术性能指标。通过页面加载监控,您可以对用户可感知到的耗时、页面性能有全面的了解。
真实用户性能指标也就是上文有所提及的
-
首次绘制时间( FP ) :即
First Paint ,为首次渲染的时间点。 -
首次内容绘制时间( FCP ) :即
First Contentful Paint ,为首次有内容渲染的时间点。 -
首次有效绘制时间( FMP ) :用户启动页面加载与页面呈现首屏之间的时间。
-
首次交互时间( FID ) :即
First Input Delay ,记录页面加载阶段,用户首次交互操作的延时时间。FID 指标影响用户对页面交互性和响应性的第一印象。 -
交互中最大延时( MPFID ) :页面加载阶段,用户交互操作可能遇到的最大延时时间。
-
完全可交互时间(TTI
) :即Time to interactive ,记录从页面加载开始,到页面处于完全可交互状态所花费的时间。 -
首次加载跳出率:第一个页面完全加载前用户跳出率。
-
慢开比:完全加载耗时超过
5s 的PV 占比。
在页面中,您可以完整清晰的查看这些指标的状况:
页面技术性能指标
页面技术性能指标中提供的指标定义来自:
指标名 | 描述 | 计算方式(以 |
---|---|---|
domainLookupEnd - domainLookupStart | ||
connectEnd - connectStart | ||
connectEnd - secureConnectionStart | ||
首字节网络请求 | 首字节响应时间(ttfb) | responseStart - requestStart |
内容传输 | 内容传输, |
responseEnd - responseStart |
domInteractive - responseEnd | ||
资源加载 | 资源加载 | loadEventStart - domContentLoadedEventEnd |
首字节 | 首字节 | responseStart - fetchStart |
DOM Ready | dom ready | domContentLoadedEventEnd - fetchStart |
慢加载列表列出了加载比较缓慢的页面,方便您进行针对性优化:
在慢加载列表中,给出了具体的
在多维分析功能中,您可以对会话性能所有的指标查询维度分布和占比情况。通过维度分析,可以发现和定位某项异常。
静态资源性能的监控,也提供了类似于上述图表的功能,且支持通过瀑布图和耗时分布图来进行其他视角的浏览。
7.2 异常监控
异常监控主要分为
在
对
您还可以查询该条
-
错误堆栈:发生错误的混淆堆栈,如果上传了
SourceMap ,则可以查看原始堆栈。 -
面包屑:用户在发生该错误前后的操作行为记录,除了系统自动收集的请求类型,还支持自定义埋点的交互事件类型。
-
自定义维度:除了系统自动采集的维度外,支持上报自定义维度。
静态资源错误和请求错误的模块都和
7.3 单点追查
单点追查的作用是可以针对特定的用户去查询在使用产品过程中的问题。目前支持了查询单个用户的日志,即日志查询。
通过输入
7.4 报警
对于监控平台来说,完善的报警系统也是必不可缺的。针对各类数据、异常创建业务相关的报警机制,有助于尽早的发现和解决问题。
报警任务中,支持创建报警策略以及对已创建好的策略进行管理。
可以很方便的对接飞书中的报警通知机器人,在接收到报警之后第一时间反馈到飞书群里:
当然,在平台中您也可以查看报警的概况、历史列表。