HTTP 推送,显著提升加载性能

上周我在斯达哥尔摩住了几天,出席了 HTTP 研讨会,参与了不少吸引人的讨论。其中一次是关于 HTTP 推送及其优缺点、早期实验结果的。

由于早期实验部署结果不那么理想,人们对 HTTP 推送大体持着怀疑态度,不过我想分享下自己更乐观一些的观点。

HTTP 推送能做哪些预加载不能做的事?

从怀疑者那里一再听到的观点是,“推送相对于预加载来说,只不过节省了一次 RTT(Round Trip Time)而已”。在实践中,这并非总是对的,有一个使用案例,推送可以完成,但预加载无法做到。

利用服务器思考时间think-time

如今,HTML 响应很少只是单纯的静态资源了。它们通常都是通过数据库获取所需的信息、使用高级语言(可能略微慢一些)动态生成的。虽然后端响应时间确实可以而且应当优化,但几百毫秒的响应时间也并不常见。

有一个常见的建议,“提早 flush” HTML,在查询数据库并构建动态内容的同时,发送 HTML 的首个 chunk 块。但是,并非所有服务端的构架都能这么简单地实现。

另外一个让问题变得困难的因素是,需要开始向浏览器发送数据时,我们尚无法确定响应的构建是否会完全成功。为避免出现响应创建逻辑出错(比如说,数据库错误或者服务端代码运行失败),我们需要在应用逻辑中创建一种“回滚”已发送响应数据的方式,并向用户展示错误信息。

尽管这肯定有可能做得到(甚至是自动化的),但目前还没有一种通用的方式能够作为协议的一部分。

因此一般场景是,Web 服务器等待后端数百毫秒以构建页面,而后开始返回数据。这时候我们就碰到了慢启动(译者注:slow start,可参考此文),所以首次 RTT 只能发送大约 14 KB 数据,第二次 28 KB 左右,如此等等。由此我们知道,将 HTML 发送出去,需要用去服务器思考时间加上慢启动时间。在思考时间期间,浏览器对接下来所需的资源一无所知,故也不会针对接下来所需资源的关键路径发送任何请求。

而且,即使我们试着耍小聪明,针对那些资源添加 preload 报头,若我们不提早 flush 文档开头,那还是没有对思考时间加以利用。

现在,将这个与使用 HTTP 推送能做的事情做个对比。服务器可以利用思考时间来推送相关的关键性资源 —— 尤其是 CSS 和 JS。这样一来,当思考时间结束时,我们极有可能已将所有关键性资源都推送给浏览器了。

还有额外好处,这些资源也预热了 TCP 连接,也提升了拥塞窗口congestion window,确保思考时间之后的首个 RTT 中,可以使用 28 KB,56 KB,乃至更大的拥塞窗口发送 HTML(这取决于思考时间的长短,以及在此期间我们推送了多少资源)。

一起来看下具体案例:一个 120 KB 的 HTML 页面,关键 CSS 有 24KB,关键 JS 有 74 KB,在 100ms RTT、无限带宽的网络环境下是如何加载的?

没有 HTTP 推送的情况下,生成 HTML 等待了 300ms,接着 4 次 RTT 发送 HTML,因为慢启动的缘故,使用了一个 RTT 请求 JS 和 CSS。在首次渲染之前,时间超过了 800 毫秒。

无推送情况下的页面加载

使用 HTTP 推送,CSS 和 JS 会在 HTML 请求到达之后尽快推送出去,发送它们需要 3 个 RTT(又一次因为慢启动),它们将拥塞窗口增大至 128 KB 左右,将要发送 HTML 时,一个 RTT 就能可以了。首次渲染总时间: 400 毫秒。

HTTP 推送情况下的页面加载

首次渲染加速了 50%!也不算很差嘛。。。

HTTP 推送不尽如意的地方

我认为人们在错误地使用 HTTP 推送的原因之一是,他们在某些并不能提供任何好处甚至损害效率的场景下使用它。

盲目推送静态资源

使用 HTTP 推送可能做的错事之一就是告诉你自己,“啊,这些资源是所有页面都需要的,把它们配置成所有页面都推送”。

这很糟糕,原因是缓存。在访问第一个页面之后,这些资源很可能就在用户的浏览器缓存中,然而你却在闷头推送。你可能会争辩说,这可比内联所有这些资源好多了。是这样的,不错,但,我必须反过来告诉你,内联资源也是糟糕的主意。

所以,若你在以这种方式盲目推送资源,请确保它是你想要内联在页面中的唯一的资源,也就是关键的 CSS。否则,你就是在冒险让重复的请求变慢。

你可能会以为,流重置stream resets会帮助推送已缓存的资源去避免浪费带宽和时间。你可能错了。很显然,并非所有浏览器会检查缓存并终止已缓存资源的推送。就算它们会这样,在流重置信号到达服务器之前,还是使用了一整个 RTT 时间发送数据。尤其是有多个资源时,这样做将可能带来大量数据浪费。

将内容放入浏览器缓存

你可能以为,推送会将资源放入浏览器缓存,可以用来做一些像使当前资源失效这样的工作。至少目前不是如此。研讨会上的讨论的话题之一就是现实问题,可能我们需要改变当前的推送行为,支持与浏览器缓存直接交互。不过当前,推送还做不到这些。推送响应进入推送缓存,只有真实请求它们时才会放到 HTTP 缓存中。

因此,如果你在推送资源,希望它们在未来的某个页面中使用,那么浏览器有可能在用到它们之前已经将它们扔出推送缓存之外了。

至少目前的实现是这样的。

填补 HTML 下发之后的管道

通常,在页面的下载循环中,使用的带宽之间会存在间隙。这意味着我们没能尽快下发资源,通常这是因为浏览器发现资源的延迟。

尽管我们应当尽量下发页面所需资源以填满这些间隙,但通常使用预加载比推送更好。预加载将缓存、cookie以及内容协商纳入考虑,它不会像推送那样存在着过度发送或错误发送的风险。就填补这些间隙而言,推送并无任何优势,所有的只是劣势。故最好不要使用推送达成此目的,使用预加载吧。

缓存摘要Cache Digests

从上面我们可以看到,HTTP 推送的一大缺点就是,服务器并不必然清楚浏览器的缓存状态,因此在推送时我们可能会将已在缓存中存在的资源推送出去。

有一个标准扩展的提案,叫做 Cache Digests。其基本思想是浏览器在 HTTP/2 连接初始化之后,向服务器发送摘要,服务器在下发资源之前能够精确判断资源是否已在浏览器缓存中存在。

该提案尚处于早期,可能需要简化,这样实现起来花费更少,不过我敢说,离开这个特性,HTTP 推送只能算半成品。

总结

HTTP 推送可以用来显著提升加载性能。正确使用时能为首个关键路径加载提速,带来性能指标的改善。

推送依然是非常新的技术,像其他所有新工具一样,在找到使用的最优方式之前,还有很长的路要走。这一路多少会有点痛苦。

是故早期实验的初始结果,可能并非全如我们所希望的那样。让我们把那些结果作为标志,指示我们关于推送的使用需要更多聪明才智吧,别妄下结论说它是无用的特性

时间: 2024-09-17 11:37:21

HTTP 推送,显著提升加载性能的相关文章

使用 React.js 的渐进式 Web 应用程序:第 2 部分 - 页面加载性能

本文讲的是使用 React.js 的渐进式 Web 应用程序:第 2 部分 - 页面加载性能, 系列第二篇,来看看基于 React 路由分块的页面加载优化. 原文地址:Progressive Web Apps with React.js: Part 2 - Page Load Performance 原文作者:Addy Osmani 译文出自:掘金翻译计划 译者:markzhai 校对者:Romeo0906,AceLeeWinnie 使用 React.js 的渐进式 Web 应用程序:第 2 部

js的压缩及jquery压缩探讨(提高页面加载性能/保护劳动成果)_javascript技巧

问题缘由:负责公司的开发平台研发工作,考虑的知识产权的保护工作,必须要考虑java的加密技术和js脚本的加密技术.在目前java加密很容易破解的情况下,还是先搞定js的加密和压缩,一方面可以提高页面加载性能,另外一方面也希望辛苦研发出来的成果得到一定的保护. 研究过程: 1.先强烈鄙视一下哪些随便转载文章的家伙,给我制造了很大的麻烦!!网上很多帖子都不靠谱.. 2.首先想了解jquery使用什么压缩的, 网上找了半天,说法不一样,后来还是在jquery官网的最频繁问题中找到了答案,但这已经是绕了

Listview的异步加载性能优化_Android

 Android中ListView是使用平率最高的控件之一(GridView跟ListView是兄弟,都是继承AbsListView),ListView优化最有效的无非就是采用ViewHolder来减少频繁的对view查询和更新,缓存图片加快解码,减小图片尺寸. 关于listview的异步加载,网上其实很多示例了,中心思想都差不多,不过很多版本或是有bug,或是有性能问题有待优化,下面就让在下阐述其原理以探索个中奥秘在APP应用中,listview的异步加载图片方式能够带来很好的用户体验,同时也

Listview的异步加载性能优化

Android中ListView是使用平率最高的控件之一(GridView跟ListView是兄弟,都是继承AbsListView),ListView优化最有效的无非就是采用ViewHolder来减少频繁的对view查询和更新,缓存图片加快解码,减小图片尺寸. 关于listview的异步加载,网上其实很多示例了,中心思想都差不多,不过很多版本或是有bug,或是有性能问题有待优化,下面就让在下阐述其原理以探索个中奥秘在APP应用中,listview的异步加载图片方式能够带来很好的用户体验,同时也是

sqlldr加载性能问题的排查

最近根据业务需要加载一批数据,在生产环境中不到半个小时就完了,可是到了测试环境,竟然跑了6个多小时,另外测试环境和生产环境的数据情况都基本差不多,主机配置也基本类似. 大家的注意力都集中到了sqlldr的加载性能上.等到他们找到我时,已经讨论了不少关于direct,convention加载的各种情况了,看似工作也做了不少了. 然后我通过邮件历史记录看到大家还讨论了可能是index导致的结果. 等到邮件转到我这的时候,已经问题算升了一个等级了.我首先要确定的就是具体的环境,在那台服务器上跑sqll

React Native JS Module 加载性能优化

关于React Native 性能 React Native 在手淘中已开始逐步推广, 在拍立淘首页的使用场景中,我们发现React Native并没有想 象中的那么快,实测效果在离线状态下性能甚至比不过H5 WindVane,React Native的UI会出现延迟渲 染存在视觉差,经过具体的代码性能测试,整个过程平均在300 ms (IPhone 5S机型下,整个JS文件 400K), 然后其核心系统调用代码加载解析整个JS (JSEvaluateScript)耗时在220 ms左右,在目前

Win10新版Build 16226推送:可以监视显卡性能了

今晨,微软为Fast Ring会员推送了Windows 10 Fall Creators Update(秋季创意者更新)的新版,升级后,系统版本号将从Build 16215升级到Build 16226. 因为上一版包含了从UI到功能层面的大量变动,所以16226比较之下,就"相形见绌"很多. 首先是Edge,提供更多关闭标签的选项.可以从Chrome迁移Cookies.设置等,Epub阅读体验优化.收藏夹支持目录树/URL编辑等.     更新还引入了一波改良的emoij表情.输入体验

JavaScript中的无阻塞加载性能优化方案_javascript技巧

Javascript在浏览器中的性能,可以说是前端开发者所要面对的最重要的可用性问题. 在Yahoo的Yslow23条规则当中,其中一条是将JS放在底部 .原因是,事实上,大多数浏览器使用单进程处理UI和更新Javascript运行等多个任务,而同一时间只能有一个任务被执行.Javascript运行了多长时间,那么在浏览器空闲下来响应用户交互之前的等待时间就有多长. 从基本层面说,这意味着<script>标签的出现使整个页面因脚本解析.运行而出现等待.不论实际的 JavaScript 代码是内

Chrome 采用新压缩算法,提升加载速度/降低流量消耗

谷歌Chrome浏览器很快就会提升网页加载速度并且降低数据流量消耗,这要归功于公司引进的Brotli压缩算法.Brotli压缩算法始于去年九月.谷歌声称和使用已经达到3年时间的Zopfli算法相比,它可以将数据压缩率继续提升26%,谷歌表示,Brotli还可以帮助降低移动设备的电池使用量,达到省电目的. 据谷歌表示,Brotli是一个全新的数据格式,在包装中容纳更多数据,而解压缩速度和其他算法大致相同.如果你希望现在就用上Brotli压缩算法,那么可以下载Chrome Canary版(谷歌用于测