前言
对于前端来说,最重要是的体验,而在前端体验中,最为外围的就是性能。秒开率、晦涩水平等一系列指标都间接影响用户体验。
因而,建设一个精确、及时、无效的前端性能监控零碎,不仅能够量化以后页面的性能程度,还能够为优化计划的成果提供数据反对,此外,还能够在页面性能下滑时提供报警服务,揭示开发人员改善页面性能。
监控指标的选取
在参考前人的实际成绩后,咱们对性能监控的一系列指标的计算成本,适用性和实用价值进行了评估,认为以下指标和信息是最具实用性和性价比的:
首先是 fcp(first contentful paint,如下图所示),这个指标是目前统计页面秒思考的支流指标,尽管它不如 fmp(First Meaningful Paint、lcp(Largest Contentful Paint)、speedIndex 等指标更贴近用户实在应用体验,然而长处是在 Android 端通过调用 Performance API 即可取得,在 iOS 能够通过 raf(requestAnimationFrame)估算,施行过程简略。
其次是 tts(time to server),这个指标并没有呈现在此前看到的文章里边。
它形容的是用户连贯到服务器的工夫,通过 Performance API 中提供的 requestStart 减去 fetchStart 失去,这个指标不是前端能够通过技术能够优化的,然而它能够反映在以后用户群体的网络环境下,页面秒开率的下限是多少。
举个例子,如果通过性能监控数据发现,有 15% 的用户拜访,须要破费至多 1s 的工夫能力连贯到咱们的服务器(能够是 SSR 服务器,也能够是 CDN),那么这些用户无论如何都不能秒开,那么此时,某页面秒开率的下限就是 85%。
如果当前情况下,这个页面的秒开率曾经达到了 75% 甚至更高,那么持续优化的边际收益会非常低,应该适可而止了。
第三是 tsp(time for server processing),这个指标也没有呈现在此前的参考文章里。
它针对的是在应用 SSR 的场景下,服务器外部解决页面申请的耗时,可通过 Performance API 中提供的 responseStart 减去 requestStart 失去。
这个环节性能太差,亦会成为连累秒开率的一个瓶颈,所以必须予以监控;tsp 太长会压迫其余环节的性能估算,太小会增大服务器运维老本。
第四是 css 文件、图片等资源的大小、xhr 申请的持续时间,前两种资源如果不加节制,会导致页面即使做到秒开,也无奈疾速进入可用状态,比方常见的 feed 流页面。
对于 xhr,须要进行分类探讨,如果是 SSR 页面,则影响不大,只有保障 tsp 处于较低水平,基本上不会连累秒开率,但如果是 SPA,页面次要功能区都依赖后端数据反对的,比方判断权限、展现 feed 流内容,xhr 的响应速度就十分要害了,也须要予以监控,在指标下滑时,告诉后端予以优化和解决。
最初是一些环境信息,比方用户实用什么品牌和型号的手机,是在微信、浏览器、还是咱们的哪个版本的得物 App 内关上 H5 页面。
当页面的性能呈现问题时,这些辅助信息能帮忙咱们尽可能精准地复现用户的实用场景,高效、精确地解决问题。
零碎架构
整个零碎由以下模块形成:
SDK:负责采集用户的页面性能数据和根本信息,依照肯定的发送策略将性能数据发往 SLS,植入页面后能够自行采集性能数据,不须要和页面代码交互。
SLS:阿里云日志服务,承受 SDK 发送的数据数据,并为性能数据增加接管工夫,ip 等附加信息。
Backend:性能数据后端服务,这个模块有两个性能,一个是定时从 SLS 拉取原始的性能数据,对其进行去重和加工,失去性能指标数据和用户信息数据,而后将这些数据分门别类地存入对应的数据表中,以备查问。另一个是为数据可视化提供接口数据。
DB:长久化解决后的性能日志数据和性能指标数据的数据库。
Report: 性能数据报表,通过和操作报表,察看特定我的项目、版本下的指定页面的各项性能指标。
各模块关系如下图所示:
关键技术决策
在进行开发之前,须要对系统的几个关键点进行思考和决策。大抵有以下几个点:
- 在挪动端,unload 事件并不是总能触发,所以须要 SDK 可能间歇性地发送数据到 SLS。为了管制发送的频率,同时缩小数据的反复量,咱们采取了一种发送距离逐渐缩短的策略,即以后页面关上的工夫越来越长,数据发送的频率会越来越低,该页面关上的工夫达到肯定长度后,SDK 将彻底进行工作。
- 因为数据存在反复,就须要对用户的端(浏览器、微信、app 内的 webview)进行指纹计算,这里咱们选用了 fingerPrintJS2,在计算时,咱们去掉了导致指纹不稳固的浏览器特色,使用户在关上页面的时候,总是有固定的指纹。然而只依赖指纹是不够的,因为同一个型号的手机,算进去的指纹很可能是一样的。所以,在对性能数据去重的时候,就要同时联合用户的指纹、日志的客户端工夫戳、用户设施的 ip 来进行去重,应用同一个 wifi,同一种设施,在同一毫秒关上页面的用户,以目前前端页面的访问量和工夫散布来判断。这个去重计划的成果还是十分好的。
- SDK 有一部分同步代码,并且须要在页面载入后尽可能及早运行。这意味着如果 SDK 报错,会导致页面无奈失常运行,这是十分危险的。所以用 try catch 包裹 SDK 的同步代码,确保 SDK 的异样不会连累页面。
- 某些页面加载的图片、发送的申请会十分多,全副记录加以上报是十分不事实的,所以咱们在监控这部分内容时,只把文件字节数排名前 10 的图片,加载时长排名前 10 的申请的详情记录下来,而后统计一下这个页面加载过多少图片,发送过多少申请。这样既晓得页面资源加载的规模,又能找到页面加载最耗时的资源。
- 原始日志抉择发送到 SLS,次要是因为这个数据发送的并发量十分大,本人做日志服务器老本过高,用 SLS 是一个比拟划算的抉择。
- 后端服务抉择用 Python+Django,Python 属于脚本语言,尽管性能差了些,然而对于前端同学来说,上手难度会低一些,对于小规模的后端服务,开发效率也能有保障。同时采纳 pypy 编译器,能够改善 python 代码的运行速度。此外,通过应用多过程 + 多线程,能够进一步提高数据的处理速度。
- 因为咱们的目标进行统计分析,所以并没有必要统计所有的性能数据,为此,咱们采取了等步长采样的办法,即针对一天的数据,咱们每 5% 的日志数据,只取前 1000 条进行统计,因为从用户侧上报数据这一行为是随机的,所以这个计划基本上能够保障采样的随机性。这样一来,统计工作的计算量就大幅降落了,保障咱们能够用一个性能很弱的机器就能够实现数据处理工作,也能够保障一旦呈现故障,咱们有工夫“追回”之前没有解决的数据。
- 数据库方面咱们抉择了 MySQL,咱们对 IO 并没有十分刻薄的需要,所以中规中矩的关系型数据库即可满足需要。
将来倒退布局
目前的前端性能监控零碎能满足日常的监控需要,然而还能够更进一步:
- 对帧率的统计:SDK 目前其实有统计帧率的性能,然而因为原始帧率的数据量过大,所以前期须要转换帧率的统计形式,例如只上报卡顿的工夫区间和该区间的帧率散布。
- 应用 lcp、fmp 等更迷信的指标来代替 fcp。
- 额定联合 pageName 去进行去重,进一步提高去重的成果。
文|老狼
关注得物技术,携手走向技术的云端