一种系统的提高速度的方法:前端在线测量

Yandex speed命令手动优化搜索结果。 盲目地做是困难的,而且常常是无用的。 因此,该公司建立了用于收集指标,测试速度和分析数据的基础架构。

Yandex介面的开发人员Andrei ProkopyukAndre_487知道关于应该使用哪些指标以及如何优化一切。



该材料基于Andrey在HolyJS会议上的讲话。 在剪切和视频下,以及报告的文本版本。


除了这份有关在线测量的报告外 ,还有Alexei Kalmakov (也来自Yandex)的一份关于离线测量的报告,在这种情况下,没有文本版本,但是有视频


Yandex搜索结果包含许多不同的块,用户查询答案的类别。 在公司中,有50多人在为他们工作,因此发行率不会下降,我们一直在关注发展。



没有人会说用户比快速界面更喜欢快速界面。 但是在开始优化之前,重要的是要了解这将如何影响您的业务。 如果这不影响业务指标,开发人员是否需要花费时间来加速界面?

为了回答这个问题,我将讲两个故事。

在发行中引入特定Web字体的历史


建立字体实验之后,我们发现呈现内容的平均时间降低了3%,即减少了62毫秒。 如果您在真空中将其作为增量,则不会太多。 肉眼可察觉的延迟仅以100毫秒开始-但是直到第一次单击的时间立即增加了一个半百分点。



用户稍后开始与页面进行交互。 点击的页面数减少了将近0.5%。 服务上的在场时间减少了,而不在场的时间增加了。



我们尚未开始推出字体功能。 毕竟,这些数字在您记住服务规模之前似乎很小。 实际上,百分之一-数十万人。

另外,速度具有累积效应。 对于一个无人认领的份额更新-0.4%将越来越多。 在Yandex中,每天都有数十种这样的功能推出,如果您不为每一个份额而战,它不会持续很长时间并达到10%。

LS缓存历史


这个故事与以下事实有关:我们将很多静态内容内联到页面中。



由于其高度可变性,我们无法将其编译为一个捆绑包或将其与外部资源一起交付。 实践表明,通过内联交付,JavaScript的呈现和初始化是最快的。

一旦我们决定使用浏览器存储库将是一个好主意。 将所有内容放入localStorage,然后在该页面上的后续条目中,从该页面加载它,而不通过网络传输它。

然后,我们主要关注指标“ HTML大小”和“ HTML交付时间”,并在它们上取得了不错的结果。 随着时间的流逝,我们发明了测量速度的新方法,积累了经验,并决定仔细检查,进行反向实验,关闭优化。



HTML的平均交付时间(优化开发时的关键指标)增加了12%,这是很多的。 但与此同时,直到绘制标题,开始解析内容之前以及初始化JavaScript之前的时间。 还减少了第一次单击的时间。 它的百分比很小-0.6,但是如果您记得比例的话...



通过禁用优化,我们使指标恶化了,只有专家可以注意到,同时用户也可以看到改善。

由此可以得出以下结论:

首先,速度确实会影响业务和业务指标。

其次,优化必须先进行测量。 如果您实施了一些不恰当的测量,那么您可能将无用。 受众的组成,设备的数量,交互场景和网络在每个地方都不相同,因此您需要检查什么才最适合您。



有一次,Ash教我们从险恶的死者中射击,然后再思考或不思考。 在速度上,您不必这样做。

第三点:测量应该反映用户体验。 例如,HTML大小和交付时间是较差的速度指标,因为用户没有坐在devTools上,也没有选择延迟较少的服务。 但是什么指标是正确的-我们将进一步说明。

什么以及如何测量?


测量应从一些关键指标开始,这些指标与HTML大小不同(例如,HTML大小)接近用户体验。



如果TTFCP(到第一个内容满涂油漆的时间)和TTFMP(到第一个内容涂满油漆的时间)指示直到第一次内容渲染的时间和重要内容渲染的时间,那么第三个是框架初始化之前的时间,这值得解释。

这是框架已经遍历页面,收集所有必要数据并挂起处理程序的时候。 如果用户此时单击某个位置,则将收到动态响应。

最后的第四个指标,即第一次互动之前的时间,通常称为互动时间(TTI)。

与html大小或交付时间不同,这些指标接近用户体验。

时间到第一次满足全涂料


为了测量用户在页面上看到第一个内容的时间,有一个Paint Timing API,到目前为止,仅适用于铬。 可以通过以下方式从中获取数据。



通过此调用,我们获得了一组渲染事件。 到目前为止,支持两种类型的事件:第一种绘画-任何呈现和firstcontentfull绘画-除空选项卡的白色背景和页面背景内容以外的任何内容呈现。

因此,我们得到一个事件数组,过滤firstcontentfull绘画并发送特定ID。

时间到第一个有意义的油漆


Paint Timing API中没有事件表示页面上已经呈现了重要内容。 这是因为每个页面上的此类内容不同。 如果我们在谈论视频服务,那么搜索结果中最主要的就是播放器-第一个非广告结果。 有很多服务,并且尚未开发通用API。 但是在这里,行之有效的成熟拐杖开始发挥作用。

Yandex中有两个拐杖学校用于度量该指标:使用RequestAnimationFrame和使用InterceptionObserver进行度量。

在RequestAnimationFrame中,使用间隔测量渲染。



假设有一些重要的内容。 这是一个类main-content的div。 脚本位于脚本的前面,其中RequestAnimationFrame被调用两次。

在第一个调用的回调中,写入间隔的下边界。 在第二个的回调-顶部。 这是由于浏览器呈现的帧结构。



首先是执行JavaScript,然后是样式分析,然后是Layout,渲染和合成的计算。

调用RequestAnimationFrame的回调在与JavaScript相同的阶段被激活,并且内容在合成期间呈现在帧的最后部分。 因此,在第一个调用中,我们仅获得下边界,该下边界会在时间上从屏幕上的像素输出中明显移除。



并排放置两个框架。 可以看出,在第一个内容的末尾呈现了内容。 我们写下在第一个回调内调用的RequestAnimationFrame的下边界,并在第二个帧内调用回调。 因此,我们获得了从在其中渲染内容的帧中调用的JavaScript到第二帧中的JavaScript的间隔。

拦截观察者


具有相同内容的第二根拐杖的工作方式不同。 这次将脚本放置在下面。 在其中,我们创建InterceptionObserver并订阅domNode。



我们没有传递其他参数,因此我们测量了它与视口的交点。 该时间记录为渲染的确切时间。



之所以可行,是因为主要内容和视口的交集是用户看到的确切交集。 设计该API的目的是准确知道用户何时看到了广告,但是我们的研究表明,这也适用于非广告单元。

在这两种方法中,最好还是使用RequestAnimationFrame:它的支持范围更广,并且我们可以在实践中更好地对其进行测试。

Js发起


想象一下一个框架,该框架具有可以订阅的某种“ init”事件,但是请记住,实际上,JS Inited既是简单指标,也是复杂指标。



很简单-因为您只需要找到框架完成事件安排的时刻即可。 复杂-因为您必须针对每个框架自行寻找这一点。

互动时间


TTI通常与先前的指标混淆,但实际上,它是浏览器主流发布时间的指示器。 在页面加载期间,执行了许多任务:从渲染各种元素到初始化框架。 只有在卸载时,才需要进行第一次交互。

长任务的概念和长任务API有助于衡量这一点。

首先是漫长的任务。



在箭头指示的简短任务之间,浏览器可以轻松填充用户事件(例如输入)的处理,因为它具有较高的优先级。 但是对于红色箭头指示的长任务,此操作将无效。

用户只有在浏览器进行输入处理后,才等到用完为止。 同时,该框架已经可以初始化,并且按钮可以运行,但是速度很慢。 这样的延迟响应是相当不愉快的用户体验。 当最后一个Long Task完成并且线程很长时间为空时,该图出现在7秒300毫秒处。

如何在JavaScript中测量此间隔?



第一步被有条件地指定为开始正文标签,然后是脚本。 这将创建一个PerformanceObserver来订阅Long Task事件。 在回调PerformanceObserver内部,事件信息被收集到一个数组中。



收集数据之后,是时候进行第二步了。 有条件地将其指定为结束标签。 我们采用数组的最后一个元素,最后一个冗长的任务,查看它完成的时刻,并检查是否经过了足够的时间。

在有关该指标的原始工作中,将5秒作为常数,但是该选择没有任何依据。 事实证明足够3秒钟了。 如果经过3秒,我们将计算直到第一次交互的时间;否则,我们将setTimeout并再次检查此常数。

如何处理数据?


需要从客户那里接收数据,以方便的方式处理和显示数据。 我们发送数据的概念非常简单。 它称为计数器。



我们将某个指标的数据传输到后端的专用笔中,并将其收集在存储库中。



此处,数据聚合通常指定为SQL查询。 以下是我们通常根据速度指标考虑的主要集合:算术平均值和百分位数组(第50、75、95、99)。



我们的数值系列中的算术平均值约为1900。它明显大于集合中大多数元素的平均值,因为这种聚合对异常值非常敏感。 此属性对我们仍然有用。



为了计算同一集合的百分位数,请对其进行排序,然后将指针放在百分位数索引上。 假设第50位,也称为中位数。 我们介于元素之间。 在这种情况下,您可以以不同的方式摆脱困境,我们将计算两者之间的平均值。 我们得到150。与算术平均值比较,可以清楚地看到百分位数对异常值不敏感。

我们考虑并使用了聚合的这些功能。 如果尝试评估用户的使用体验,则排放的算术敏感性是一个缺点。 实际上,用户可以始终从例如火车上连接到网络,并破坏选择。

但是在监视方面,相同的灵敏度是一个优势。 为了不遗漏重要问题,我们使用算术平均值。 它很容易转移,但是在这种情况下误报的风险并不是很大的问题。 总比忽略好。



此外,我们考虑中位数(如果将其附加到时间指标上,则中位数是满足50%的请求的时间的指标)和第75个百分点。 目前有75%的要求符合要求,我们将其作为整体速度的估算值。 第95个百分位数和第99个百分位数被认为可以测量缓慢的长尾巴。 这些是非常大的数字。 95th被认为是最慢的请求。 第99个百分点是异常的。

计算最大值没有意义。 这就是疯狂的方式。 在计算出最大值之后,可能会发现用户已经在等待页面加载20年了。

考虑了汇总之后,仅需应用这些数字即可,最明显的方法是将它们显示在图形中。



在图表上,我们实时找到最完整的绘画指标以进行搜索。 蓝线代表台式机的动态,红线代表移动设备的动态。

我们必须不断监视速度图,并将这项任务委托给机器人。

监控方式


由于速度指标易变,并且在不同时期会不断波动,因此需要对监视进行微调。 为此,我们使用挫折感的概念。

调试是随机过程更改其特征(例如方差或数学期望)的时刻。 在我们的案例中,这是平均样本。 如前所述,平均值对排放敏感,非常适合监控。



这是发生对齐并由机器人记录事件的图形示例。 他如何将这一刻与其他许多犹豫分开? 为了理解这一点,我们施加了其他数据。



黄色图是度量指标,蓝色图是周期足够大的移动平均值。 红色是平均值加三个标准偏差。 绿色是相同的,只是带有减号。



红色和绿色指示器形成安全的走廊。 尽管指标和移动平均线在它们之间波动-一切正常,但这是普通波动。 但是,如果他们离开安全区,则会触发监视。



检查功能的速度


讨论的全部内容都与一个已经启动的项目的速度数据一起使用,但是我想在将单个功能部件投入大规模生产之前测量其速度。 为此,我们使用A / B测试-对照组和实验组的指标比较。



我们将用户分为对照组和实验组。 每个插槽的读数分别收集,汇总并制成表格。



通常,在A / B测试中,也使用算术平均值。 在这里,我们看到一个变化量,为了准确地确定这是事故还是重大结果,我们进行了统计检验。



由于在计算中使用了Mann-Whitney检验,因此将其命名为“ MW”。 在其帮助下,可以计算出所谓的“正确率”。 该指标具有阈值,之后我们将增量视为真实。 此处设置为99.9%。

当测试达到此值时,增量将在界面中突出显示。 我们称之为着色。 在这里,我们看到绿色,即按时上色满满颜料的良好着色。 第一次进行有意义的绘画的时间未达到此值,即增量也不错,但不是99.9%。 完全不可能相信她。 在初始化框架和进行交互的时间后,肯定会看到不良的红色。 从中我们可以得出与字体相同的结论。



你自己怎么做?


您可以通过两种方式实现速度测量。 首先是自己做所有事情。



一个用于从客户端接收数据的句柄,一个后端,将所有这些都放入数据库,MongoDB,PostgreSQL,MySQL,任何DBMS(它们具有开箱即用的聚合)以及许多开源解决方案之一-以便绘制图形并安排监视。

第二种解决方案是使用Yandex Metric或Google Analytics(分析)分析系统。 在Yandex Metrics的示例中,它看起来像这样。



以下是该指标为用户提供的即用型指标。 当然,这还不是以上所有内容,而是已经存在的东西。 其余的可以通过用户设置手动添加。 还提供A / B测试和监视。

结论


我们讨论的在线速度测量的概念称为RUM-实际用户监视。 我们非常爱她,以至于我们甚至画出了酷酷的摇滚变音符号。



这种方法之所以有用,是因为它基于现实世界中的数字,即服务受众所拥有的指标。 使用指标,您似乎可以从每个用户那里获得反馈。 因此,请开始优化,不要停止。
公告结束。 如果您喜欢与HolyJS 2018 Piter进行的这次演讲,您可能会对即将在11月24日至25日举行的即将举行的HolyJS 2018莫斯科感兴趣。 在这里,您不仅可以看到许多其他 JS报告,还可以在报告后的讨论区域中询问任何发言人。 明天,即11月1日起,门票价格将上涨至最终价格,因此,今天是最后一次以折扣价购买门票的机会!

Source: https://habr.com/ru/post/zh-CN426571/


All Articles