Web加速的最佳HTTP / 2优先级


HTTP / 2承诺将大大加快网络速度,而Cloudflare早就为所有客户端部署了HTTP / 2访问。 但是HTTP / 2优先级的一项功能没有达到预期。 不是因为它从根本上被破坏了,而是因为在浏览器中的实现。

今天,Cloudflare提供了更改HTTP / 2优先级的方法,这使我们的服务器可以控制优先级决策,从而真正加快了Internet的速度。

从历史上看,是由浏览器来控制如何以及何时下载Web内容。 今天,对于所有付费计划,我们都在对该模型进行重大更改。 他们将控制权直接转移给站点所有者。 在Cloudflare仪表板的“速度”选项卡上,客户端可以启用“高级HTTP / 2优先级”:它将默认的浏览器设置覆盖到改进的计划方案中,从而显着加快了访问者的访问速度(在某些情况下,增加了50%)。 借助Cloudflare工作者,站点所有者可以走得更远,并完全根据其特定需求自定义设置。

现状


网页包含数十个(有时数百个)单独的资源,这些资源由浏览器下载并收集到最终显示的内容中。 这包括用户与之交互的可见内容(HTML,CSS,图像),以及网站本身,广告,分析和营销跟踪信标的应用程序逻辑(JavaScript)。 从用户的角度来看,这些资源的加载顺序非常重要:这会影响他看到内容并可以与页面进行交互的时间。

实际上,浏览器是一个HTML处理引擎,它遍历HTML文档并按照以下说明进行操作:从头到尾HTML,在页面移动时构建页面。 样式表链接(CSS)告诉浏览器如何设置页面内容的样式,浏览器将延迟内容的显示,直到加载样式表为止。 页面上的脚本可能具有不同的行为。 如果脚本被标记为“异步”或“待处理”,则浏览器可以继续处理文档,并在可用时简单地运行脚本。 如果脚本没有被标记为异步或延迟的,则浏览器必须停止处理文档,直到脚本被加载并执行。 这样的脚本称为“阻止”,因为它们阻止浏览器继续处理文档。

HTML文档分为两部分。 <head>文档的标题位于开头,并且包含样式表,脚本和其他显示内容所需的浏览器说明。 标题为<body>文档的正文之后,它包含浏览器窗口中显示的实际内容(尽管脚本和样式表也可以位于正文中)。 在浏览器到达文档正文之前,用户什么都没有显示,并且页面保持空白。 因此,尽快处理标头很重要。 如果您对这些细节感兴趣, HTML5 Rocks网站上有一个很好的教程 ,介绍了浏览器的工作方式。

浏览器通常负责构建页面和进一步处理文档所需的各种资源的加载顺序。 在HTTP / 1.x中,对浏览器一次可以从任何服务器请求多少个对象(通常是6个连接,每次连接一次仅一个资源)有限制,因此,请求的顺序由浏览器严格控制。 在HTTP / 2中,情况完全不同。 浏览器可以立即请求所有资源(至少在发现资源后立即请求),并向服务器提供有关如何交付这些资源的详细说明。

最佳资源加载顺序


对于大多数部件而言,页面加载周期中存在一个最佳顺序,该顺序可以最大程度地为用户提供页面可用性(最佳和非最佳加载顺序之间的差异可以达到50%或更大)。

如上所述,在浏览器可以显示任何内容之前, <head>部分中的CSS和JavaScript阻止了该内容。 在此阶段,使用100%的渠道来加载阻止资源,而不是按顺序加载它们,因为它们是用HTML代码编写的,这会带来更大的利润。 这使浏览器可以在加载下一个阻止资源时分析和运行每个元素,从而创建最佳的管道。



并行或顺序加载的脚本加载时间没有不同,但是对于顺序加载,可以在第二次加载期间处理和执行第一个脚本。

加载阻塞资源后,情况变得更加有趣。 在此,最佳负载可能取决于特定的站点,甚至取决于业务优先级(用户生成的内容或广告的选择或分析等)。 字体的另一个问题,因为浏览器在将样式表应用于显示的内容后会检测到所需的字体。 因此,当浏览器发现字体时,有必要在屏幕上显示已经准备好显示的文本。 加载字体的任何延迟都会导致屏幕上没有文本(或文本以错误的字体显示)。

通常,需要考虑一些折衷:

  • 页面(视口)可见部分中的自定义字体和图像应尽快加载。 它们在加载页面时直接影响用户的视觉体验。
  • 应相对于其他JavaScript资源按顺序加载非阻塞JavaScript,以便可以对每个资源进行管道传输。 JavaScript可能包括自定义应用程序逻辑以及用于分析和营销的跟踪信标,并且它们的延迟可能导致企业跟踪的指标减少。
  • 图像可以并行上传。 图像文件的前几个字节包含其大小,这对于浏览器布局可能是必需的,并且渐进式图像的并行加载可以在传输约50%的总体积后提供视觉完整性。

考虑到折衷,在大多数情况下,此策略效果很好:

  • 自定义字体将按顺序下载,并与范围内的图像共享可用带宽。
  • 可见图像被并行加载,在它们之间共享分配给它们的部分带宽。
  • 没有更多字体或可见图像时:
    • 非阻塞脚本将顺序加载,并与不可见图像(超出范围)共享可用带宽。
    • 并行加载不可见图像,它们之间共享分配给它们的部分带宽。

因此,尽可能快地加载用户可见的内容,将应用程序逻辑延迟到最小,并以尽可能快地完成布局的方式加载不可见的图像。

例子


为了说明,请使用典型电子商务网站中的简化产品类别页面:

  • 蓝色 -页面本身的HTML文件。
  • 绿色 -一份外部样式表(CSS文件)。
  • 橙色 -四个外部脚本(JavaScript)。 页面顶部的两个阻塞脚本和两个异步的脚本。 阻止脚本以较深的橙色阴影显示。
  • 红色是一种自定义Web字体。
  • 紫色 -13张图片。 页面徽标和四个产品图像显示在查看窗口中,另外8个产品图像需要滚动。 五个可见图像由较深的紫色阴影指示。

为简单起见,假设所有资源具有相同的大小,并且每个负载在1秒钟之内。 下载所有资源总共需要20秒,但是加载的顺序和方法非常重要。



这是浏览器中最佳资源加载的外观:



  • 加载HTML,CSS和阻止脚本的前4秒页面为空白:它们都使用100%连接。
  • 在4秒标记处,显示的背景和页面结构没有文本或图像。
  • 一秒钟后(大约5秒钟),将显示页面文本。
  • 在5到10秒的时间间隔内,图像开始下载,一开始模糊,但是很快它们就变得清晰了。 在大约7秒时,结果与最终版本几乎没有区别。
  • 在大约10秒钟时,页面可见部分中所有视觉内容的加载完成。
  • 在接下来的两秒内,将加载并执行异步JavaScript,并执行所有非关键逻辑(分析,市场营销标签等)。
  • 在最后8秒钟内,如果用户滚动页面,则会加载其余图像。

当前浏览器优先级


当前所有的浏览器引擎都实现了各种优先级排序策略 ,但都不是最优的。

Microsoft Edge和Internet Explorer 不支持优先级设置 ,因此它们使用默认的HTTP / 2设置,该设置并行加载所有内容,并在所有资源之间平均分配带宽。 未来版本中的Microsoft Edge将切换为使用Chromium引擎,这可能会改善这种情况。 但是就目前而言,在我们的示例中,浏览器大部分时间都停留在页面标题中,因为图像会减慢阻止脚本和样式表的传输。



在视觉上,这会带来相当痛苦的体验:用户在空白屏幕上查看19秒钟,然后延迟1秒钟来显示文本。 查看下面的动画时,请耐心等待,因为在19秒钟内,黑屏似乎没有任何反应(尽管确实如此):



Safari表示,Safari 会并行加载所有资源,并根据其重要性共享带宽(阻止资源(如脚本和样式表)比图像更重要)。 图像是并行加载的,但也与阻止内容同时加载。



尽管Safari与Edge类似,在某种意义上说,所有内容都是同时加载的,但分配更多带宽以阻止资源可以让您更早地显示内容:



  • 大约8秒钟后,样式表和脚本的加载完成,因此您可以开始呈现页面。 由于图像是并行加载的,因此它们也可以部分显示(渐进图像的模糊图像)。 这仍然是最佳方案的两倍,但比Edge中要好得多。
  • 大约11秒钟后,将加载字体。 您可以显示文本。 此时,正在为图像加载更多数据,并且图像变得更加清晰。 这可与7秒钟大关的最佳负载情况相媲美。
  • 在剩余的9秒钟内,随着下载更多数据,图像变得更加清晰,直到最终该过程在20秒钟内完成。

Firefox创建了一个对资源进行分组的依赖树,然后计划这些组一个接一个地加载或在组之间共享带宽。 在此组中,资源共享带宽并同时​​加载。 计划将图像加载在阻止渲染的样式表之后,然后并行加载,但是阻止渲染的脚本和样式表也将并行加载,并且不会从流水线中受益。



在我们的示例中,这比Safari快一些,因为图像正在等待样式表加载:



  • 大约6秒钟时,原始页面内容就会显示出来,并带有产品图片的背景和模糊版本(相比之下,Safari的显示时间为8秒钟,最佳情况下为4秒钟)。
  • 在8秒钟时,字体就会加载,您可以显示文本以及产品的图像更加清晰(最好的情况是Safari的11秒和7秒)。
  • 在剩余的12秒钟内,图像会随着加载剩余内容而变得更加清晰。

Chrome (以及所有基于Chromium的浏览器)会优先考虑广告资源。 这对于阻塞按顺序最佳加载的资源非常有效,但对图像却不太好。 在开始下一个图像之前,每个图像最多可加载100%。



实际上,这是一种几乎最佳的下载方案,唯一的区别是图像是一次下载而不是并行下载:



  • 加载Chrome最多需要5秒钟,这与最佳方案相同,在第4秒显示背景,在第5秒显示文本。
  • 在接下来的5秒钟内,可见区域的图像一次加载一次,直到该过程在10秒钟左右完成(与最佳方案相比,当它们在7秒钟左右以略微模糊的形式显示并在剩下的三秒钟变得清晰时)。
  • 页面的可视部分在10秒内完成(与最佳方案相同),其余10秒用于运行异步脚本和加载隐藏图像(与最佳方案一样)。

视觉比较


尽管从技术上加载所有内容需要花费相同的时间,但外观上的差异还是很大的:



服务器端优先级


客户端(浏览器)请求HTTP / 2优先级,服务器必须根据该请求决定要做什么。 大量服务器根本不支持此功能,其余服务器满足客户端请求。 另一个选择是根据客户端请求确定最佳的服务器端优先级。

根据规范 ,HTTP / 2优先级排序是一个依赖关系树,需要完全了解所有当前请求,以便能够相对于彼此优先化资源。 这使您可以实施难以置信的复杂策略,但是很难在浏览器或服务器端很好地实现它(如各种浏览器策略和不同级别的服务器支持所证明)。 为了简化优先级管理,我们开发了一种更简单的方案,该方案仍然具有最佳计划所需的所有灵活性。

Cloudflare的优先级划分方案由64个优先级“级别”组成,并且在每个级别中都有确定如何在彼此之间划分连接的资源组:



首先,所有资源都以较高的优先级下载,然后过渡到较低的级别。

在给定的优先级级别内,存在三个不同的并发组:

  • 0 :组“ 0”中的所有资源使用100%带宽按请求顺序依次发送。 仅在加载组“ 0”的所有资源之后,才会考虑处于相同级别的其他组。
  • 1 :并发组“ 1”中的所有资源按其请求顺序依次发送。 可用带宽在并行度组“ 1”和并行度组“ n”之间平均分配。
  • n :并行传输并发组“ n”中的资源,共享可用带宽。

实际上,并行组“ 0”对于需要顺序处理的关键内容(脚本,CSS等)很有用。 “ 1”组对于不太重要的内容很有用,这些内容可以与其他资源共享带宽,但是资源本身仍然可以从顺序处理(异步脚本,非渐进式映像等)中受益。 并发组“ n”对于受益于并行处理的资源(渐进式图像,视频,音频等)很有用。

Cloudflare默认优先级


通过高级优先级选项,实现了如上所述的资源加载的“最佳”顺序。 应用的特定优先级如下:



此方案使您可以顺序发送阻止渲染的资源,然后并行发送可见图像,然后以某种程度的带宽共享发送其余页面内容,以平衡应用程序和内容的负载。 需要注意的是*如果Detectable是并非所有浏览器都可以区分不同类型的样式表和脚本,但是在所有情况下它都将更快。 加速50%,尤其是对Edge和Safari访问者而言,不会有什么异常:



设定工作人员的优先级


更快的默认工作很棒,但是由于借助Cloudflare Workers支持配置优先级的能力,它变得非常有趣,因此站点可以重新定义资源的默认优先级或实现自己的优先级方案。

如果工作程序将cf-priority标头添加到响应中,则Cloudflare边缘服务器将应用指定的优先级和并发性。 标头格式为<priority> / <concurrency>,因此response.headers.set('cf-priority', “30/0”); 将为该答案设置优先级30和并行度0.类似地,“ 30/1”将并行度设置为“ 1”,而“ 30 / n”会将并行度设置为n。

通过这种灵活性,站点可以为其需求设置任意的资源优先级。 例如,为了提高某些重要的异步脚本或主映像的优先级:甚至在浏览器确定它们在范围内之前就下载它们。

为了通知优先级决策,工作程序的运行时还会在请求对象中指示浏览器请求的关于优先级的信息,该信息将传递给工作程序事件的接收者(request.cf.requestPriority)。 传入优先级是用分号分隔的属性列表。 看起来像这样: weight=192;exclusive=0;group=3;group-weight=127

  • weight :用于优先化HTTP / 2的权重。
  • Exclusive :专有的HTTP / 2标志(对于基于Chromium的浏览器,为1;对于其他浏览器,为0)。
  • group :请求组的HTTP / 2流标识符(对于Firefox,非零)。
  • group-weight :HTTP / 2请求组的权重(对于Firefox,非零)。

这仅仅是开始。


配置和控制答案优先级的能力是未来工作的主要基础。 我们打算在此基础上引入我们自己的高级优化,但是在工作人员的支持下,所有站点和研究人员都可以尝试各种优先级策略。 通过Apps Marketplace,公司还可以在工作平台上创建新的优化服务,并将其提供给其他站点使用。

如果您使用的是Pro计划或更高级别的计划,请转到Cloudflare仪表板中的“速度”选项卡,然后启用“高级HTTP / 2优先级”以加快站点速度。

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


All Articles