嗨,我叫Stas Makeev。 在Yandex,我领导着Turbo页面技术的开发,该技术即使在连接速度较慢的情况下也可以快速加载内容。 今天,我将向Habr的读者介绍我们项目的架构。
用户的幸福感在很大程度上取决于他查看网页内容的速度。 速度让许多人担心:在移动应用商店中,只有Speedtest的安装量就超过一亿。 提供商,移动运营商,网站和应用程序开发人员努力提供最快的内容访问权限,以使客户满意。
俄罗斯移动网络的平均下载速度为
16.26 Mbit / s-这是一个很好的指标。 但是连接速度并不均匀,我们仍然面临缓慢的Internet连接-3G,2G和EDGE。 当然,您在咖啡馆,购物中心,公路上或乡村中,惯常的高速速度大大降低了:站点加载了数十秒甚至更长的时间。
Turbo页面技术解决了访问内容的问题,包括低或不稳定的连接速度。 对于网站所有者而言,这一点很重要,因为在从搜索过渡期间,访问者“下降”的比例降低了。

Turbo Page如何工作
网站所有者在Yandex.Webmaster中注册RSS提要。 该提要进入Turbo Pages内容系统,该系统每隔几分钟进行一次更新。 大量内容-主要是图片和视频-我们缓存并布置在CDN中。 除了RSS之外,还可以通过API和自动解析器传输内容。
Turbo页面的缓存图像量接近100 Tb
系统的可靠性和容错性对我们很重要,因此我们制作了多个数据副本并将它们存储在我们的三个数据中心中。 在每个数据中心,数百台服务器每秒处理数千个请求,这使您可以灵活地平衡负载。
Turbo Pages内容系统应单独张贴,我们将进行撰写。 目前,我们只限于简化方案。

在浏览器中打开URL会怎样?
当用户转到“ Turbo”页面时,“在幕后”会发生类似以下的情况:
HTTP适配器处理用户的HTTP请求,并向AppHost和report-renderer中的所需图形发出请求。
AppHost是一个特殊的组件,它封装了源之间的网络交互,称为依赖图。 在此图上按拓扑排序的顺序询问源;所有业务逻辑都缝在它们和图配置中。 特别是,在图形级别,将轮询KV存储并将数据请求发送到第三方API。
Report-renderer是一个用node.js编写的应用程序,它接受JSON输入,执行用JS编写的模板并返回一个字符串。
所有这些几乎都是瞬间发生的。
什么影响下载速度?
我们正在研究速度的各个方面:从在平衡器上实现HTTP / 2到优化TLS握手,再到手动优化SVG。 在这种情况下,您需要了解最终用户速度的组成。
在团队内部,我们区分了请求处理的三个阶段:服务器,网络和客户端。
伺服器这包括数据中心中发生的所有事情:从HTTP请求到达我们的服务器的那一刻到直接发送到客户端的HTML页面的生成。
服务器上的请求处理时间应最少。 尽管值相对较小,但它绝对影响所有用户查询。 此外,所有过程都在我们受控的环境中进行-根本不能为大的延误找借口。
服务器时间由源依存关系图的各个顶点之间的网络交互以及每个顶点的运行时间组成。 但是,我们不会专注于Yandex数据中心的网络基础结构的功能-应该单独发布它们。
我想更加关注第二个部分-每个峰的执行时间。 举例来说,让我们看一下与Report-renderer组件配合使用的原理和工具,该组件负责生成HTML。 对于其他组件,它们非常相似。
在我们的CI流程中,有一些任务会在dev中接受拉取请求,这些任务会对对功能分支的每次提交执行基本检查。 如果任何指标超过了指定的限制,则在确定原因之前冻结对dev的影响。
现阶段的关键指标:
我们根据数据收集每个页面的客户端静态信息(CSS和JS),但是带有块的捆绑包本身与请求无关,因此只需将分支中文件的大小与dev中的类似文件进行比较即可。 对于不同类型的文件,我们设置了不同的阈值,在这些阈值之后,如果不对速度负责,则不能将任务倒入dev中。
通常,对代码进行联合分析并寻找优化方法。
我们必须对页面大小指标和模板时间采取不同的行动,因为它们高度依赖于特定请求,并且需要某种统计确定性。 此外,您不能进行综合查询,因为这将是不诚实的衡量标准。 因此,我们不断收集用户对访问日志的随机请求,从中形成“墨盒”,并在分支中使用更改和开发人员的模板“拍摄”它们。 这使您即使不是很受欢迎的请求也可以捕获更改。
我们有几个“请求栏”,使我们能够覆盖到Turbo页面的大部分流量。
除了优化模板之外,我们还遵循V8内部进行的优化。 例如,切换到
TurboFan可获得出色的结果:服务器端模板化时间显着减少。

切换到TurboFan后,服务器模板时间减少
联播网在网络部分,我们包括客户端和服务器之间发生的所有事情:数据传输时间,页面大小和静态信息以及资源缓存。 这已经更加有趣了,因为从我们舒适的数据中心中,我们发现自己处在野外的世界中,那里并非一切都取决于我们。 测量变得有些复杂,而且最重要的是-您可以在几百毫秒内获得真正的实际结果。
这是我们的工作。
我们扭曲了TCP和TLS参数,使您可以赢得多个RTT(往返时间),这在具有高延迟的网络中提供了出色的结果。 我们的同事已经
写过有关此内容的文章,因此我不会深入探讨。
传输数据的大小会极大地影响下载速度,因此我们尝试以最有效的方式仅发送当前页面所需的内容。
我们的界面中的图片使用ImageOptim进行了优化。 为了优化SVG,我们不仅使用
SVGO ,而且我们也不懒于研究内容,如果可能的话,可以手动对其进行优化。
我们将网站所有者的图像上传到针对图像渲染进行了优化的特殊CDN。 通过首先将图像转换为sRGB,我们可以裁剪图像的exif和颜色配置文件。 比特率降低为每个通道8位,压缩级别设置为85。lanczos滤波器用于调整大小。
考虑到像素密度(视网膜显示),我们为每张图片创建了数十个选项,以组合不同的屏幕尺寸。 当然,如果浏览器支持,我们会自动以WebP格式对图像进行编码。
如果浏览器支持,则使用gzip / zopfli和brotli压缩文本格式(HTML,JavaScript,CSS)。
重要的是不要忘记用户与服务器之间的距离。 Turbo页面在许多地区使用,内容可以是任何页面。 因此,即使在最偏远的地区,我们也使用CDN(不断扩展),我们不会妥协并减少延迟。
当然,最快的查询是他们根本不这样做。 所有静态数据均由不带cookie的独立域提供永久缓存,并且要增加缓存命中率,仍可以在主页和带有搜索结果的页面上额外对其进行预热。
顾客仅仅形成服务器响应并将其通过网络传递给浏览器还不够,仍然需要有效地显示它。 我们优化了呈现页面的开始时间,以便人们开始更快地阅读内容。
在HTML标头中,我们“预热”与静态分发服务器的连接,并预加载它。 样式内联到页面中,这允许浏览器开始呈现页面,而无需等待样式通过网络加载。
内容图像,嵌入和广告不会立即加载,而是在它们阅读页面时(靠近用户的视野)加载。
JavaScript部分嵌入HTML中,所有其他脚本最后都通过单独的HTTP请求加载。 对于入门,错误和指标收集至关重要的脚本,以及页面上不常见的组件都嵌入在页面中。
我们收集RUM页面加载指标。 最关键的是:所有脚本均已完成初始化且用户可以使用页面之前,直到第一个字节,第一个绘图和开始交互的时间。
大多数用户不是直接访问Turbo页面,而是从其他Yandex服务直接访问,我们希望根据用户体验来评估页面加载时间。 不仅是在真空中获取抽象时间,而且还是衡量用户如何看待一切的指标。
因此,我们制定了积分速度指标:
max (firstContentfulPaint, firstImageLoadTime, timeToVisible) — timeToClick
其中:
- timeToClick-导致显示Turbo页面的绝对单击时间。 可以单击搜索结果页面上的摘录,也可以单击Yandex.Zen中的卡片。
- firstImageLoadTime-第一个屏幕中第一个内容图像的绝对加载时间。
- timeToVisible-页面进入可见状态的绝对时间。 对于在后台加载页面的情况,这是正确的。
并获得了用户体验指标:
- 如果屏幕的2/3被尚未加载的图像占用,则firstContentfulPaint度量的完整性非常可疑;
- 链接上有很多事件处理程序,在单击和加载页面的实际开始时间之间可能会经过非零时间,我想了解一下。

我们正在不断开发技术,以使网站吸引更多的访客。 现在,Turbo页面的平均加载速度是普通移动版本的15倍。 数以万计的网站都使用Turbo,并且访问它们的总次数超过120亿。
所有这些都是开发人员,支持服务,与网站所有者合作的经理以及其他许多人工作的结果。 随着时间的推移,团队当然会扩大。 例如,现在我们正在寻找
前端和后端专家 ,很高兴见到新的同事。
您希望将来阅读Turbo Page技术的哪些组件? 您会对什么经验感兴趣? 我们也欢迎您提供反馈和想法。 谢谢你