原文地址:HTTP/2 Prioritization
原文做者:[Patrick Meenan]
译文出自:FE-star/speed
译者:smallbonelunginx
以正确的顺序请求页面资源对于快速的用户体验相当重要。想象一下,若是一个网页上有一堆图片,还有一个外部样式表,一些自定义Web字体和一些在head
中的脚本。若是浏览器首先下载了全部图片而且最后加载了样式表,在全部内容都加载完毕前,页面将彻底是空白页。若是浏览器首先加载了全部阻塞资源,接着是Web字体和图片,那么它能够更早地呈现页面,并让用户开始看到内容,同时加载其他的图片。我在Chrome浏览器性能工做上的大部分时间都花在了尝试优化加载资源的顺序以得到最佳用户体验上。git
使用HTTP/1.x
,浏览器能够彻底控制资源加载顺序。每一个链接一次只能支持一个资源请求,服务器会尽快返回请求的内容。浏览器能够经过决定什么时候请求资源以及打开多少个并行链接来安排请求。github
HTTP/2
让这些事情变得更好也更复杂了。浏览器能够一次请求多个资源,指定一些优先级信息来帮助肯定应该如何处理这些资源,而后等待服务器发回全部数据,而不是一次请求一个。若是浏览器和服务器都支持优先级,则应使用浏览器指定的规则并使用全部可用带宽来传递资源,而不会有资源之间的相互竞争。web
每一个资源都获取一个stream ID
来标识链接上的资源,而且有三个参数用于定义资源优先级:算法
root stream 0
。浏览器不必定同时知道全部资源,所以服务器可以在新请求到达时从新肯定请求的优先级也很关键。浏览器
那么......咱们是怎么作的呢?安全
这包括使用Chromium的优先级逻辑和网络堆栈的全部内容。服务器
Chrome是惟一使用独占位的浏览器,它在每一个资源上使用它。它构建了一长串资源,将较低优先级的资源连接到仍在等待的最后一个相同或更高优先级的资源。若是没有更高优先级的资源挂起,则启动新链。权重以静态映射的方式分配,Chrome的五个内部优先级分别对应相应的权重(即HIGHEST为256)。网络
假设给定几个请求队列,全部请求都设置了独占位,服务器将选择权重最高的一个,完成传递后,就将其从列表中弹出并从新选择。架构
假设Chrome正确构建了排序,这可能很是有效。独占下载资源是样式表和脚本等阻塞资源的最佳选择。当涉及到图片和视频时,你可能须要一些交错执行的任务(特别是对于渐进式图片)。不然,在转到下一个请求前,你将要等待每一个图片或视频彻底下载下来。
Firefox实现了HTTP/2
的树结构,并构建了一个虚拟的数据流树,用来对不一样请求类型进行分组。Firefox对分组进行了加权,以便为更重要的组提供更多的带宽,而且当全部节点都已完成时,空闲周期(idle cycles)可用于响应。
在根级别中,有一个“leader”组,,它的带宽是“Other group”的两倍。在“leader”组中,有一个叫“follower”的子组,它只有在“leader”组的直系后代完成下载后才会开始下载。例如,在权重为200的“leader”组下面,一旦全部CSS完成下载后,图片和字体才会开始下载。一个组内的全部子资源具备相同的权重并均匀分配带宽(同时下载全部图片或全部脚本)。
从总体结构上来看Firefox很是出色,能够为推测请求定义空闲周期,但对同时下载全部资源优先级的划分并非很好。像样式表和脚本等这样的阻塞资源的优先下载要比按顺序下载它们才能让解析器处理文档要好。
这包括iOS上的全部浏览器(包括Chrome)。
Safari采用了一种很是简单的方法,看起来是SPDY优先级的遗留部分。五个内部webkit优先级静态映射到权重,而且没有定义依赖关系。全部请求基于每一个资源的优先级来划分带宽权重进行同时下载(例如,脚本得到图片带宽的三倍)。
这样致使高并发性并非很好,并且落后于Firefox的实现,在Firefox中至少follower组的资源会等到leader组资源所有完成任务以后(尽管它可能不足以证实Firefox中树的复杂性)。
简而言之,Microsoft Edge(和Internet Explorer)根本不支持优先级。全部请求均匀分配带宽(几乎是最糟糕的状况)。
如今大多数服务器都支持HTTP/2
了,一般也"支持"优先级的。支持加了引号,是由于即便一个服务器内部支持资源优先级,实际上让它可以与浏览器工做也须要调整网络堆栈并尽量减小输出缓冲而不影响吞吐量。
缓冲多是一个问题,由于服务器能够发送一堆低优先级的响应,这些响应在高优先级响应到来以前已经在缓冲区中排队。发送高优先级响应时,没法抢占已缓冲的低优先级响应。缓冲能够来自服务器自己,TLS层,TCP发送的缓冲,甚至来自网络上的bufferbloat,跟踪并消除全部多余的缓冲可能会很复杂。我在今年早些时候的一篇博文中谈到了一些缘由和解决方案,但这并非一个详尽的清单。
为了测试服务器优先级的有效性,我构建了一个测试页面,你能够在你的服务堆栈上部署该测试页面以查看优先级是否正常工做。它专门针对Chrome的优先级逻辑,所以最好使用慢速链接上的Chrome进行测试。它先将3MB低优先级图片排队,而后在下载并执行高优先级脚本后,脚本会发送4个高优先级请求(一张图片,一个页面背景,一个自定义的webfont和一个阻塞脚本)。当优先级正常工做时,后置的高优先级请求的资源会跳太低优先级请求并快速获得响应:
当优先级工做不正常时,部分或所有后置的高优先级请求的资源会被延迟,直到优先级较低的请求完成为止:
后置请求的阻塞脚本的延迟超出了“DOM Content Loaded”的度量值,字体和2个图片的延迟对视觉体验产生了至关大的影响:
为了跟踪CDN和托管服务提供商支持HTTP/2
优先级的程度,Andy Davies建立了一个GitHub仓库,用于跟踪当前的支持情况,任何人均可以提交测试结果来群策群力。在撰写本文时,状况很是糟糕,只有两个CDN确实正确地肯定了优先级,而且存在一些很是使人震惊的失败(例如每一个云提供商甚至Google的GFE)。但愿经过提升对这种状况的认知,咱们将可以为优先级提供更普遍的支持。
对托管和服务器来讲,好消息是你老是能够在它们以前配置一个支持优先级的CDN来解决问题(尽管直接支持它会很好)。
在浏览器方面,除了敦促浏览器厂商以得到更好的支持以外,没有太多能够作的事情。其中的一些厂商可能会遇到架构问题,如他们的浏览器引擎在操做系统的网络堆栈层之上,致使没法传递优先级信息。多是个人偏见,但我认为Chrome是最接近“正确”的作法,但仍有至关大的改进空间。
HTTP/3
也即将到来,但目前的优先级方案不会改变。这个改变是网络堆栈的终结。在服务器端,这意味着操做系统的缓冲和拥塞控制再也不起做用,服务器软件100%负责最小化缓冲(包括拥塞控制算法以最小化缓冲区)。
那么就说到这里,但愿为了HTTP/2
和一个安全,高性能的网络,咱们能够在2019年修复资源优先级。