Cloudflare的HTTP/2优化策略

文 / Patrick Meenan


译 / John


原文 


https://blog.cloudflare.com/better-http-2-prioritization-for-a-faster-web/


HTTP/2意味着更快的网页加载速度,而Cloudflare在很久之前也为所有客户提供了HTTP/2访问服务。但是其中HTTP/2的一项特性——加载优先级,并没有达到预期的效果。事实上优先级特性本身并没有什么问题, 真正地问题在于浏览器中优先级特性的实现方式。


现在,Cloudflare推出了对于HTTP/2优先级的优化升级,也就是让我们的服务器有能力控制优先级策略从而真正提高网页的加载速度。在此之前,浏览器已经能够控制并决定加载网页内容的方式与时长。而现在我们希望能通过对优先级模型进行升级,将网页控制权尽可能地交给网站所有者。客户可以在Cloudflare仪表板的“Speed”选项卡中启用“增强HTTP/2优先级”——将升级的调度方案覆盖至浏览器默认设置从而显著提升网页访问体验(根据多个场景下的测试,我们发现性能普遍提升达50%)。借助Cloudflare Workers,网站所有者可以根据需求进一步定制用户的网页浏览体验。


背景


Web页面一般由数十个甚至数百个单独的资源组成,浏览器将这些资源加载并组装成最终显示的内容。这包括用户与之交互的可见内容(HTML、CSS、图像)以及网站本身的应用程序逻辑(JavaScript)、广告、跟踪网站使用情况的数据分析与营销跟踪信标等。根据何种优先级策略对这些资源的加载过程进行排序,直接决定用户等待网页加载所需要的时间以及查看网页内容并与其进行交互的体验。


浏览器本质上是一个HTML处理引擎,每当加载一个网页时,浏览器会遍历HTML文档并遵循指示,按照从HTML开始到结束的顺序构建页面;与此同时,浏览器也会引用层叠样式表(CSS)从而获悉并设置页面内容的样式;一些情况下,为了明确设置要显示的内容样式,浏览器会延迟显示网页内容直到层叠样式表被加载完成。文档中引用的脚本可能有以下几种不同的行为:如果脚本被标记为“异步”或“延迟”,则浏览器可以继续处理文档并在脚本可用时运行脚本代码;如果脚本没有被标记为“异步”或“延迟”,则浏览器必须停止处理文档,直到脚本下载完成并被执行才会继续处理文档,这些没有被标记的脚步被称为“阻塞”脚本——顾名思义,“阻塞”脚本阻止浏览器继续处理文档直到其被加载和执行。


HTML文档分为两部分:<head>文档的开头部分包含显示内容所需的浏览器样式表、脚本和其他说明;<body>文档位于头部文件之后,包含浏览器窗口中显示的实际页面内容(脚本和样式表也被包含在其中)。在浏览器访问至文档正文也就是<body>之前,网页不会向用户显示任何内容,页面将保持空白。因此,浏览器需要尽可能快地加载头部文件。


在处理文档的同时,通常浏览器也负责确定以什么样的顺序加载构建页面所需的不同资源。在HTTP/1.x的情况下,浏览器单次从任一服务器端所请求的内容量被限制(通常是6个连接,每个连接一次只能请求一个资源),所以资源的加载顺序是由浏览器通过请求的方式严格控制的。而对于HTTP/2,情况发生了很大的变化,浏览器可以一次请求所有的资源(至少了解有多少资源等待被加载),从而便于其向服务器提供有关资源传输的详细说明。


最优资源排序


大多数浏览器在加载页面的过程中存在最佳的加载资源优先级策略,其直接促成了良好的用户体验;同时最佳策略与非最佳策略所造成的网页加载耗时可能存在高达50%的差异。


如上所述,在浏览器呈现全部网页内容之前的页面加载时期,会在CSS上被阻止并阻止HTML的<head>部分中的JavaScript;所以在这一期间最好使用全部连接带宽以充分下载被阻塞的资源,并按照HTML定义的顺序一次下载一个资源以便于浏览器在下载下一个阻塞资源时可同时解析并执行上一个项目,实现下载和执行的流水线化操作。

Cloudflare的HTTP/2优化策略

传统的并行下载或依次下载所需要的下载时间相同,而如果按照顺序下载并在第二个脚本下载时执行第一个脚本,那么这会明显缩短网页资源的加载时间。


一旦加载渲染项阻止内容,最佳加载状态可能取决于特定网站甚至业务优先级情况(如用户内容与广告分析对提供商而言的权重)。其中尤为重要的一项的是字体,浏览器仅在将样式表应用于即将显示的网页内容之后才会确认所加载字体。因而当浏览器确认所加载字体前,现存的即将被显示在网页上的文本就应当被准备完毕。获取字体过程所发生的任何延迟最终都会导致屏幕上显示空白文本或以错误字体显示文本。


为确保网页加载的正常,我们应当权衡以下内容:


  • 应尽快加载页面可见部分中的自定义字体与图像——这直接关乎页面加载时期的用户视觉体验。


  • 非阻塞JavaScript相对于其他JavaScript资源应当以串行方式下载,同时每个JavaScript都以流水线形式加载。JavaScript可能包括面向用户的应用程序逻辑、用户行为分析与营销跟踪信标,一旦出现延迟即可导致业务跟踪指标的下降。


  • 借并行下载可实现更好的图像加载效果。图像文件的前几个字节包含浏览器页面布局所需要的图像尺寸,并行的逐行图像下载允许在浏览器仅接收原始数据的50%基础之上优先完成视觉上的图像加载。


权衡以上内容,我们可得出以下可达到良好运作状态的策略:


  • 按顺序策略下载自定义字体,并使用可见图像分割可用带宽。


  • 按并行策略下载图像,切割“图像”以便于按照所分配的带宽逐行加载图像。


  • 当没有更多等待被处理的字体或图像时:


  • 非阻塞脚本按顺序下载,并使用不可见的图像分割可用带宽。


  • 按并行策略下载不可见图像,切割“图像”以便于按照所分配的带宽逐行加载图像。


通过采取以上策略,我们希望浏览器能够尽可能快地加载用户可见的网页内容,尽可能减少应用程序逻辑所造成的延迟,并以尽可能短的时间完成网页布局与不可见图像的加载。


实际案例


为了便于说明,我们将以电子商务网站的简化产品类别页面作为典型案例,其中页面具有以下加载项:


Cloudflare的HTTP/2优化策略 页面本身的HTML文件,使用蓝色框表示。


Cloudflare的HTTP/2优化策略 1个外部样式表(CSS文件),使用绿色框表示。


 Cloudflare的HTTP/2优化策略 4个外部脚本(JavaScript),使用橙色框表示。其中2个在页面开头处的脚本为阻塞脚本,使用较暗的橙色阴影框表示;除此之外还有2个异步脚本。


Cloudflare的HTTP/2优化策略 1个自定义Web字体,使用红色框表示。 


Cloudflare的HTTP/2优化策略 13个图像,使用紫色框表示。页面徽标和4个产品图像在视口中可见,使用较深的紫色框表示;8个产品图像需要滚动页面才能看到。


为简单起见,我们假设以上所有资源的大小相同,每个资源在访问端需要1秒时间连接与下载,加载所有资源总共需要20秒,这里我们主要研究采用不同的加载方式会对用户浏览网页的体验带来什么影响。

Cloudflare的HTTP/2优化策略

这就是我所描述的采用“最佳加载策略”加载资源时,浏览器所呈现出的效果:

Cloudflare的HTTP/2优化策略

  • 启用全部连接,加载HTML、CSS和阻止脚本的前4秒内,页面为空白。

  • 第4秒,页面仅显示了背景与结构却未显示文本与图像。

  • 第5秒,页面文本被成功显示。


  • 5~10秒,图像逐渐被加载;开始时图像模糊,随后图像被快速锐化;第7秒时浏览器几乎完成了全部图像加载


  • 第10秒,视觉窗口中的所有可视化内容都已加载完毕。


  • 10~12秒,异步JavaScript被加载与执行,随后包括数据分析、营销信标在内的其他所有非关键逻辑被加载与执行。


  • 12~20秒,其他的产品图像开始被加载以便为用户接下来可能的网页滚动行为做好准备。


常见浏览器的优先级策略


常见的几个浏览器引擎都采取了不同的优先级策略,耐人寻味的是其中没有一个符合“最佳优先级加载策略”的要求。


1)Microsoft Edge和Internet Explorer


Microsoft Edge和Internet Explorer 不支持加载项的优先级排序,因而所有内容的加载方式都基于HTTP/2的默认设置,即并行加载所有内容并为所有内容均匀分配带宽。预计在未来,采用Chromium引擎的新版Microsoft Edge会在此方面迎来极大改善。而在我们的示例页面中,并行加载与均匀带宽分配意味着浏览器的绝大部分加载过程都停留在头部文件之上,而图像等资源则会减慢阻塞脚本与样式表的传输速度。

Cloudflare的HTTP/2优化策略

在大多数内容被成功显示之前,用户视觉会在长达19秒的时间内不得不停留在空白页面,随后经历1秒的文本显示延迟才能看到网页所有元素。这就意味着用户使用IE内核的浏览器观看动画时需要耐心等待页面元素全部加载完成,这无疑是对用户浏览网页体验的巨大影响。

Cloudflare的HTTP/2优化策略

2)Safari


Safari 同样采取并行策略加载所有资源,但Safari会根据不同资源的重要程度为其划分合适且足够的带宽(例如:渲染脚本和样式表等阻塞资源比渲染图像更为重要);而图像虽采用并行加载的策略,但其也与阻塞渲染资源同时被加载。

Cloudflare的HTTP/2优化策略

虽然采用了与Edge类似的并行加载策略,但Safari通过为阻塞渲染资源分配更多带宽,实现更快的网页加载过程:

Cloudflare的HTTP/2优化策略

  • 加载开始后的约8秒,样式表和脚本已加载完毕,因而页面开始被显示;由于图像采用并行加载策略,在此期间只有部分图像被加载(相对于采用逐行加载策略的图像而言更加模糊),但加载效果要远胜于IE与Edge浏览器。


  • 约第11秒,字体已加载完毕,文本正常显示的同时有更多带宽被投入图像数据的加载当中,这让图像的清晰程度进一步提升,这样的水平已经接近于采用“最佳加载策略”的第7秒加载效果。


  • 接下来的9秒当中,随着完成下载的数据进一步增多,图像变得愈发清晰,直到第20秒完成全部加载活动。


3)Firefox


Firefox构建一个依赖关系树,该树将资源分组并安排这些组采取依次加载或组之间共享带宽的形式进行加载。在给定组内,资源在共享带宽的同时被下载;而那些图像则被计划在阻塞渲染资源之后,采用并行策略的方式进行加载,但阻塞渲染脚本和样式表也会被并行加载,这样便无法从流水化操作中获得显著的性能提升。

Cloudflare的HTTP/2优化策略

在我们的示例中,由于图像加载过程被推迟到样式表加载完成之后,因而最终的实际加载过程会略快于Safari。

Cloudflare的HTTP/2优化策略

  • 第6秒,背景与产品图像的模糊版本构成了网页的大致内容。其整体观感和Safari在第8秒时的加载效果与采用“最佳加载策略”浏览器的第4秒加载效果相似。 


  • 第8秒,字体已加载完毕,文本正常显示的同时图片愈发清晰(其与Safari在第11秒时的加载效果与采用“最佳加载策略”浏览器的第7秒加载效果相似)。


  • 剩余的12秒内,产品图像逐渐变得更加清晰。


4)Chrome


Chrome以及所有基于Chromium内核的浏览器会将资源按照一定优先级顺序排序至待加载列表中,这对于阻塞渲染资源来说非常有效;按顺序加载策略为这些资源的加载过程所带来的好处不言而喻,但其页面中的图像在开始下一张图像之前需要加载至100%才可成功显示。

Cloudflare的HTTP/2优化策略

在实际测试中,Chrome的加载效果几乎与采用“最佳加载策略”的浏览器相同,唯一的区别是Chrome的图像采用按顺序加载的方式一次性加载完毕而非并行加载:

Cloudflare的HTTP/2优化策略

  • 前5秒,Chrome体验与采用“最佳加载策略”的浏览器相同——前4秒背景加载完毕,第5秒文本加载完毕。


  • 5~10秒,可见图像被依次下载直到第10秒时全部图像加载完毕(与采用“最佳加载策略”的浏览器相比,Chrome在第7秒时,其图像稍微模糊但在随后的3秒内被快速锐化)。


  • 10秒后,页面的可视部分资源加载完毕(此成绩与采用“最佳加载策略”的浏览器相同),接下来的10秒则会被用于运行异步脚本并加载隐藏图像(此策略与采用“最佳加载策略”的浏览器相同)


视觉比较


上述浏览器的不同加载策略所体现出的视觉差异可能会十分明显,即使这些浏览器厂商都花费了足够多的时间与技术来优化页面资源加载过程:

Cloudflare的HTTP/2优化策略

服务器端的优先级


客户端(浏览器)请求HTTP/2优先级排序策略,随后由服务器根据请求决定接下来做什么。很多服务器根本不支持使用优先级做任何事情,但是对于那些支持优先级的服务器,它们都尊重客户端的请求。我们可以通过考虑客户端的请求来决定在服务器端使用何种最佳优先级。


根据规范,HTTP/2优先级可以看作是一个依赖树,此依赖树需要完全掌握所有正在进行的请求以便能够考虑到所有资源的加载状况并优先决定关键资源的加载。由于不同的浏览器具有不同的加载策略,而不同层级的服务器各有差异,这种十分复杂的优先级策略很难在浏览器端被轻易实现。为了便于优先级的管理,我们开发了一种更简单的优先级排序方案,该方案具有优化调度所需优先级的灵活性。


Cloudflare优先级排序方案由64个优先级“级别”组成,在每个优先级内,一组资源可确定如何在不同优先级之间共享连接:

Cloudflare的HTTP/2优化策略

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


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


  • 0:并发“0”组中的所有资源按照请求的顺序使用100%的带宽依次发送。只有所有并发“0”组的资源被下载完成之后,浏览器才会考虑同一级别的其他组。


  • 1:并发“1”组中的所有资源按请求顺序依次发送。可用带宽在并发“1”组和并发“n”组之间均匀分配。


  • n:并发“n”组中的资源是按照每个资源所分配的带宽资源并行发送。


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


Cloudflare默认优先级


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

Cloudflare的HTTP/2优化策略

该优先化方案允许串行发送并呈现阻塞内容,随后并行发送可见图像。接下来通过某种程度的共享,覆盖页面内容的其余部分以平衡应用程序和内容加载。这里的“*If Detectable”警告是说,并非所有浏览器都区分不同类型的样式表和脚本,但这不影响浏览器的加载速度。默认情况下Cloudflare会比其他浏览器,特别是Edge和Safari快50%。

Cloudflare的HTTP/2优化策略

人为可控的自定义优先级


尽管在默认情况下Cloudflare可实现更快加载速度,但真正有趣的是配置优先级的能力也向Cloudflare Workers公开,这样站点就可以覆盖资源的默认优先级,或者实现它们自己的完整优先级计划。


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


借助上述灵活性举措,站点可以调整资源优先级以满足其多样化需求。例如,当浏览器识别出用户正在阅读某一网页时,用户的视觉重心位于当前网页之上;而如果我们想要提升下一页的观感,那么我们可以尝试提升某些关键异步脚本的优先级或增加关键图像加载的优先级。


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


  • weight:HTTP/2优先级的浏览器请求权重。


  • exclusive:浏览器请求的HTTP/2独占标志(基于Chromium的浏览器为1,其他为0)。


  • group:请求组的HTTP/2流ID(Firefox仅为非零)。


  • group-weight:请求组的HTTP/2权重(Firefox仅为非零)。


这仅仅是个开始


浏览器调整和控制响应优先级的能力可以让许多未来相关项目从中受益。而我们则是在此基础之上加入了独创的高级优化——也就是让整个优先级排序过程暴露给开发者以便于开发者基于网站其他研究人员的参考信息尝试不同的优先级策略。通过Apps Marketplace,我们还在Workers平台之上构建新的优化服务,并使其可供其他站点使用。

————————————————

版权声明:本文为CSDN博主「LiveVideoStack_」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/vn9PLgZvnPs1522s82g/article/details/90684091


「视频云技术」你最值得关注的音视频技术公众号,每周推送来自阿里云一线的实践技术文章,在这里与音视频领域一流工程师交流切磋。

Cloudflare的HTTP/2优化策略

上一篇:VIPKID 张武锋:自研RTC的故事


下一篇:滴滴李先刚:语音识别在复杂场景的性能将显著提升