HTTP/2 优先级


HTTP/2保证了更快的Web和Cloudflare不久以前为所有客户推出了HTTP/2的访问。但HTTP/2的一个特性,优先级,不是因为它从根本上被打破了常规,而是因为浏览器实现它的方式。

今天,Cloudflare正在推动对HTTP/2优先级的更改,这使我们的服务器能够控制优先级决策,从而真正提高Web的速度。

历史上,浏览器已经控制决定加载Web内容的方式和时间。今天,我们正在为所有付费计划对该模型进行彻底改变,直接将控制权交给网站所有者。客户可以在Cloudflare仪表板的“速度”选项卡中启用“增强的HTTP/2优先级”:这将通过改进的调度方案覆盖浏览器默认设置,从而显着提高访问者体验(我们在多个场合看到的速度提高了50%)。借助Cloudflare Workers,网站所有者可以更进一步,并根据自己的特定需求完全定制体验。

背景

网页由数十个(有时数百个)单独的资源组成,这些资源由浏览器加载和组装到最终显示的内容中。这包括用户与之交互的可见内容(HTML,CSS,图像)以及网站本身的应用程序逻辑(JavaScript),广告,跟踪网站使用情况的分析以及营销跟踪信标。对这些资源的加载方式进行排序会对用户查看内容和与页面交互所需的时间产生重大影响。

浏览器基本上是一个HTML处理引擎,它遍历HTML文档并按照从HTML开始到结束的顺序遵循说明,随着它的进行构建页面。对样式表(CSS)的引用告诉浏览器如何设置页面内容的样式,浏览器将延迟显示内容,直到它加载样式表(因此它知道如何设置要显示的内容的样式)。文档中引用的脚本可能有几种不同的行为。如果脚本被标记为“异步”或“延迟”,则浏览器可以继续处理文档,并在脚本可用时运行脚本代码。如果脚本没有标记为异步延迟,则浏览器必须停止处理文档,直到脚本下载并执行为止,然后再继续。这些被称为“阻塞”脚本,因为它们阻止浏览器继续处理文档,直到它们被加载和执行。

HTML文档分为两部分。文档的<head>位于开头,包含显示内容所需的浏览器样式表,脚本和其他说明。文档的<body>位于头部之后,包含浏览器窗口中显示的实际页面内容(尽管脚本和样式表也允许在主体中)。在浏览器到达文档正文之前,没有任何内容可以显示给用户,页面将保持空白,因此尽可能快地浏览文档的头部非常重要。如果你想深入了解细节,“HTML5 rocks”有一个关于浏览器如何工作的精彩教程。

浏览器通常负责确定加载构建页面所需的不同资源的顺序并继续处理文档。在HTTP/1.x的情况下,浏览器限制它可以一次从任何一个服务器请求多少内容(通常每个连接一次有6个连接和一个资源),因此排序严格由浏览器的方式请求。使用HTTP/2,事情变化非常显着。浏览器可以立即请求所有资源(至少一旦它知道它们),它就向服务器提供有关如何传递资源的详细说明。

最优资源排序

对于页面加载周期的大多数部分,存在最佳的资源排序,这将导致最快的用户体验(并且最佳和非最佳之间的差异可能很大 - 多达50%或更多。

如上所述,在浏览器可以呈现任何内容之前的页面加载周期的早期,它在CSS上被阻止并阻止HTML的<head>部分中的JavaScript。在加载周期的这一部分期间,最好使用100%的连接带宽来下载阻塞资源,并按照HTML中定义的顺序一次下载一个。这使得浏览器在下载下一个阻塞资源时解析并执行每个项目,允许下载和执行流水线。

图1

当并行下载或一个接一个地下载脚本时,脚本花费相同的时间下载,但是通过顺序下载它们可以处理第一个脚本并在下载第二个脚本时执行。

一旦加载渲染阻止内容,事情会变得更有趣,最佳加载可能取决于特定网站甚至业务优先级(用户内容与广告与分析等)。特别是字体可能很难,因为浏览器仅在将样式表应用于即将显示的内容之后才发现它需要的字体,所以当浏览器知道字体时,需要显示已经存在的文本准备好被吸引到屏幕上。获取字体的任何延迟最终都会在屏幕上显示空白文本(或使用错误的字体显示文本)。

通常需要考虑一些权衡:

  • 应尽快加载页面可见部分(视口)中的自定义字体和可见图像。它们直接影响用户对页面加载的视觉体验。
  • 非阻塞JavaScript应该相对于其他JavaScript资源以串行方式下载,因此每个JavaScript的执行都可以通过下载进行流水线操作。JavaScript可能包括面向用户的应用程序逻辑以及分析跟踪和营销信标,并且延迟它们可能导致业务跟踪的指标下降。
  • 图像可以从并行下载中受益。图像文件的前几个字节包含浏览器布局可能需要的图像尺寸,并行的逐行图像下载可以在视觉上完成,传输的字节大约占50%。

权衡这些权衡,一种在大多数情况下运作良好的策略是:

  • 自定义字体按顺序下载并使用可见图像分割可用带宽。
  • 可见图像并行下载,在其中分割带宽的“图像”份额。
  • 当没有更多字体或可见图像待处理时:
    • 非阻塞脚本按顺序下载,并使用不可见图像分割可用带宽
    • 不可见的图像并行下载,在它们之间分割带宽的“图像”份额。

这样,尽可能快地加载用户可见的内容,尽可能少地延迟应用程序逻辑,并且以尽可能快地完成布局的方式加载不可见图像。

范例

为了便于说明,我们将使用典型电子商务网站的简化产品类别页面。在此示例中,页面具有:

  • 页面本身的HTML文件,由蓝色框表示。
  • 1个外部样式表(CSS文件),由绿色框表示。
  • 4个外部脚本(JavaScript),由橙色框表示。其中2个脚本在页面开头处阻塞,2个脚本是异步的。阻止脚本框使用较暗的橙色阴影。
  • 1个自定义Web字体,由红色框表示。
  • 13个图像,用紫色框表示。页面徽标和4个产品图像在视口中可见,8个产品图像需要滚动才能看到。5个可见图像使用较深的紫色。

为简单起见,我们假设所有资源都是相同的大小,每个资源在访问者的连接上下载需要1秒。加载一切总共需要20秒,但如何加载它会对体验产生巨大影响。

图2

这就是所描述的最佳加载在资源加载时在浏览器中的样子:

图3

  • 在加载HTML,CSS和阻止脚本的前4秒内,页面为空白,全部使用100%的连接。
  • 在4秒标记处,显示页面的背景和结构,没有文本或图像。一秒钟后,在5秒钟,显示页面的文本。
  • 从5-10秒开始,图像加载,开始时模糊但非常快速地锐化。大约7秒钟的标记几乎与最终版本无法区分。
  • 在10秒标记处,视口中的所有可视内容都已完成加载。在接下来的2秒内,加载并执行异步JavaScript,运行任何非关键逻辑(分析,营销标签等)。
  • 在最后的8秒内,其余的产品图像会加载,以便在用户滚动时准备就绪。

当前浏览器优先级

所有当前的浏览器引擎都实现了不同的优先级策略,其中没有一个是最佳的。

Microsoft Edge和Internet Explorer不支持优先级排序,因此所有内容都回退到HTTP/2默认设置,即并行加载所有内容,在所有内容之间均匀分配带宽。Microsoft Edge将在未来的Windows版本中使用Chromium浏览器引擎,这将有助于改善这种情况。在我们的示例页面中,这意味着浏览器在大部分加载时间都停留在头部,因为图像正在减慢阻塞脚本和样式表的传输速度。

图4

在大多数内容显示之前,在视觉上会导致在空白屏幕上盯着空白屏幕19秒,然后显示文本的延迟时间为1秒。在观看动画进度时请耐心等待,因为对于19秒的空白屏幕,它可能感觉没有任何事情发生(即使它是):

图5

Safari并行加载所有资源,根据Safari认为它们的重要性来划分它们之间的带宽(使用脚本和样式表等渲染阻塞资源比图像更重要)。图像并行加载,但也与渲染阻止内容同时加载。

图6

虽然类似于Edge,所有内容同时下载,但通过为渲染阻止资源分配更多带宽,Safari可以更快地显示内容:

图7

  • 大约8秒后,样式表和脚本已完成加载,因此页面可以开始显示。由于图像是并行加载的,因此它们也可以在其部分状态下呈现(对于渐进图像而言模糊)。这仍然是最佳情况的两倍,但比我们用Edge看到的要好得多。
  • 在大约11秒时,字体已加载,因此可以显示文本并且已下载更多图像数据,因此图像将更加清晰。这与最佳装载情况下7秒标记周围的体验相当。
  • 对于剩余的9秒加载,图像变得更清晰,因为下载的数据越多,直到最终在20秒完成。

Firefox构建一个依赖关系树,该树将资源分组,然后安排这些组要么一个接一个地加载,要么在组之间共享带宽。在给定组内,资源共享带宽并同时​​下载。这些映像计划在渲染阻塞样式表之后加载并且并行加载,但渲染阻塞脚本和样式表也会并行加载,并且不会获得流水线操作的好处。

图8

在我们的示例中,由于图像被延迟到样式表完成之后,因此最终会比Safari快一点。

图9

  • 在6秒标记处,初始页面内容使用产品图像的背景和模糊版本进行渲染(与Safari的8秒和最佳情况的4秒相比)。
  • 在8秒时,字体已加载,文本可以与产品图像的稍微更清晰的版本一起显示(相比于Safari的11秒和Optimal案例中的7秒)。
  • 对于剩余的12秒加载,产品图像在剩余内容加载时变得更清晰。

Chrome(以及所有基于Chromium的浏览器)将资源优先排序到列表中。这对于渲染阻止内容非常有效,这些内容可以从按顺序加载中受益,但对图像效果不佳。在开始下一张图像之前,每张图像加载到100%完成。

图10

在实践中,这几乎与最佳装载情况一样好,唯一的区别是图像一次加载一个而不是并行加载:

图11

  • 直到5秒标记,Chrome体验与最佳情况相同,显示背景为4秒,文本内容为5。
  • 在接下来的5秒内,可见图像一次加载一个,直到它们在10秒标记处全部完成(与最佳情况相比,它们在7秒时稍微模糊并且在剩余的3秒内锐化)。
  • 在页面的可视部分在10秒完成后(与最佳情况相同),剩余的10秒用于运行异步脚本并加载隐藏图像(就像最佳加载情况一样)。

视觉比较

在视觉上,影响可能非常显着,即使它们都花费相同的时间来技术上加载所有内容:
图12

服务器端优先级

客户端(浏览器)请求HTTP/2优先级排序,由服务器根据请求决定做什么。许多服务器不支持在确定优先级时执行任何操作,但对于那些服务器,它们都支持客户端的请求。另一个选择是考虑客户端的请求,决定在服务器端使用的最佳优先级。

根据规范,HTTP/2优先级是一个依赖树,它需要完全了解所有正在进行的请求,以便能够相互优先考虑资源。这允许非常复杂的策略,但很难在浏览器或服务器端实现良好(由不同的浏览器策略和不同级别的服务器支持证明)。为了使优先级更易于管理,我们开发了一种更简单的优先级方案,该方案仍然具有优化调度所需的所有灵活性。

Cloudflare优先级划分方案由64个优先级“级别”组成,在每个优先级内,有一组资源可确定如何在它们之间共享连接:

图13

在进入下一个较低优先级之前,将转移所有较高优先级的资源。

在给定的优先级内,有3个不同的“并发”组:

  • 0:并发“0”组中的所有资源按照请求的顺序依次发送,使用100%的带宽。只有在下载了所有并发“0”组资源之后,才会考虑同一级别的其他组。
  • 1:并发“1”组中的所有资源按请求顺序依次发送。可用带宽在并发“1”组和并发“n”组之间均匀分配。
  • n:并发“n”组中的资源是并行发送的,将它们之间可用的带宽分开。

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

Cloudflare默认优先级

启用时,增强的优先级实现上述资源的“最佳”调度。应用的特定优先级如下所示:

图14

该优先化方案允许串行发送呈现阻止内容,然后并行发送可见图像,然后通过某种程度的共享来覆盖页面内容的其余部分以平衡应用程序和内容加载。“* If Detectable”警告是,并非所有浏览器都区分不同类型的样式表和脚本,但在所有情况下它仍然会明显更快。默认情况下快50%,特别是Edge和Safari访客并不罕见:

图15

自定义工人的优先级

默认情况下更快,但事情变得非常有趣的是,配置优先级的能力也暴露给Cloudflare Workers,因此站点可以覆盖资源的默认优先级或实现自己的完整优先级方案。

如果Worker为响应添加“cf-priority”标头,则Cloudflare边缘服务器将使用指定的优先级和并发响应。标头的格式是<priority> / <concurrency>,所以像response.headers.set('cf-priority',“30/0”);对于给定的响应,将优先级设置为30,并发度为0。类似地,“30/1”将并发设置为1,“30 / n”将并发设置为n。

通过这种灵活性,站点可以调整资源优先级以满足其需求。例如,在浏览器识别出它们位于视口中之前,提升某些关键异步脚本的优先级或增加图像的优先级。

为了帮助通知任何优先级决策,Workers运行时还在传递给Worker的fetch事件侦听器(request.cf.requestPriority)的请求对象中公开浏览器请求的优先级信息。传入的请求优先级是以分号分隔的属性列表,其类似于:“weight = 192; exclusive = 0; group = 3; group-weight = 127”。

  • weight:HTTP/2优先级的浏览器请求权重。
  • exclusive:浏览器请求的HTTP/2独占标志(基于Chromium的浏览器为1,其他为0)。
  • group:请求组的HTTP/2流ID(Firefox仅为非零)。
  • group-weight:请求组的HTTP/2权重(Firefox仅为非零)。

这仅仅是个开始

调整和控制响应优先级的能力是许多未来工作将从中受益的基本构建块。我们将在它之上实现我们自己的高级优化,但是通过将它暴露在Workers中,我们还向网站和研究人员开放,以尝试不同的优先级策略。通过Apps Marketplace,公司还可以在Workers平台之上构建新的优化服务,并使其可供其他站点使用。

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

最后

我希望你发现这篇文章有用!你可以关注我的博客。请在下面的评论中留下任何问题。我很乐意帮忙!


文章作者: 左智文
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 左智文 !
评论
  目录