使用不变缓存加速网页

Firefox 49 发布时包含了Cache-Control: Immutable 功能,允许网站提示哪些 HTTP 资源永远不会更改。几乎同时,Facebook 开始广泛部署此更改的服务器端。他们使用一种 URI 版本控制开发模型,该模型与 immutable 非常匹配。这极大地影响了 Firefox 中 Facebook 重新加载的性能。看起来其他内容提供商也将采用它。

immutable 的好处在于,当页面刷新时(这是一种非常常见的社交媒体场景),之前使用 HTTP 响应标头标记为 immutable 的元素无需与服务器重新验证。缺少此提示,浏览器需要猜测哪些对象在重新加载时可能更改或可能不更改——一方面浪费时间,另一方面冒着网站不兼容的风险。

对于较小的对象,通过 304 HTTP 响应代码进行此重新验证的工作量几乎与完全传输响应一样多。

事实证明,这可以节省大量工作。页面的 JavaScript、字体和样式表在重新加载之间不会更改。更重要的是,数十张图像也不会改变——标记可能会包含不同的图像,但单个图像的内容不会改变。实际上,唯一可能改变的是标记本身。

对于重新加载 Facebook 内容的 Firefox 用户来说,这是一个巨大的福音——最快的请求是一个从未发出的请求,而这正是刷新 Facebook 页面时一遍又一遍发生的事情。在我的测试中,一个典型的 Feed 最初可能包含 150 个不同的资源。在 Firefox 49 中按下刷新只会生成 25 个网络请求。

meta-chart

正如您可能想象的那样,这极大地加快了速度。在我的测试中,它通常可以将页面重新加载时间缩短一半。Facebook 也是 Brotli 压缩编码的早期采用者。他们使用它来减少动态标记的带宽使用量(无法缓存),与旧的 gzip 标准相比,节省了大约 20% 的传输字节。Brotli 在 Firefox 44 之后一直可用。

当然,Facebook 的服务器也是最大的赢家——从未发出的请求节省了带宽和 CPU 利用率,而这些资源可以反过来用于为其他请求加快网站速度。

“此更改有效地消除了来自最新版 Firefox 的重新验证请求,这在许多情况下可以将加载时间缩短几秒。” – Nathan Schloss,Facebook 软件工程师

 

我们正在发展壮大

 

Facebook 一直是这项工作的优秀合作伙伴。最近,我一直在宣传 immutable,其他开发人员也开始采用它。

BBC 已在试用阶段采用了它

据轶事报道,BBC 发现重新加载时间最多提高了近 50%,并且发现 immutable 消除了 90% 的请求。

星际文件系统 这样面向未来的实现也对此很感兴趣

还有像Squid 代理 这样久负盛名的产品

sq

它现在在现实世界中积累了足够的经验,可以强烈推荐使用。为了确保充分的文档,它也被纳入了IETF 的标准轨道。您只需要一个正确的缓存标头 即可开始开发。

关于 Patrick McManus

Mozilla 的首席工程师,专注于平台网络

更多 Patrick McManus 的文章…


28 条评论

  1. Jeff R.

    “只有 25 个网络请求”

    当这样的陈述被期望听起来令人印象深刻时,你就知道有些地方不对劲了。

    2017年1月26日 上午10:43

    1. Jay

      图像始终是单独的网络请求。鉴于 Facebook 上最独特的内容往往是用户上传的内容(以及广告内容),我建议不要过早下结论。

      2017年2月9日 上午10:01

  2. Gerd Neumann

    任何想要阅读 Squid 代理图像的人:https://hacks.mozilla.ac.cn/wp-content/uploads/2016/12/sq.png

    2017年1月26日 上午11:42

  3. Jeremie

    我很高兴我们正在解决资源过度获取以及它在加载页面时导致的减速问题。

    “Expires:” 应该只做这篇文章中描述的“immutable”所做的事情。但不知何故,Mozilla 和其他浏览器都没有尊重过期日期,并且即使在将来有一个日期,也继续重新验证资源。
    请参阅 RFC:https://tools.ietf.org/html/rfc7234#section-5.3

    从您写的内容来看,这似乎是一个设计选择,以便编写不佳的网站不会遇到过期日期配置错误的问题。

    在“expires”之后,添加了“Cache-control: max-age”。它具有相同的目的,但具有更细粒度的功能。请参阅 RFC:https://tools.ietf.org/html/rfc7234#section-5.2.2.8
    。浏览器再次开始在刷新页面时忽略缓存,以规避缓存控制标头的错误网站配置。

    immutable 会像前两次尝试那样遭遇同样的命运吗?
    将来我们会看到“really-immutable”标志吗?:-)

    如果网站开始滥用新值,并且由于陈旧资源导致出现问题,Mozilla(和其他 Web 浏览器)是否会开始重新验证那些已被声明为 immutable 的资源?

    2017年1月26日 下午12:58

    1. Patrick McManus

      请参阅以下评论中关于区分新鲜和当前的区别

      2017年1月27日 上午04:49

  4. Joshua Sinkfield

    我认为任何形式的缓存都是保持互联网可信赖的好方法。

    2017年1月26日 下午14:48

  5. Jason Brown

    真是太棒了!

    对于我们这些在第三世界国家或在拥有第三世界互联网的第一世界国家(向新西兰致敬!)的人来说,Facebook 是一个巨大的数据消耗!

    我们的太平洋岛屿收取着世界上一些最高的互联网费率,同时承受着一些最低的工资率——至少对于那些幸运到能获得工资的人来说是这样。

    与大多数国家一样,Facebook 在岛屿上非常受欢迎,因为家庭第一、朋友第二和“面对面”沟通第三的重要性。因此,50% 的数据节省将对那里的人们产生巨大影响。

    您是否知道此缓存功能是否已在全球部署,或者像往常一样,先在第一世界部署,最后在第三世界部署?

    2017年1月26日 下午15:58

  6. Omega

    这会被 CTRL+F5 覆盖,是吗?

    2017年1月26日 下午17:17

    1. Patrick McManus

      是的,这种“强制重新加载”样式用于修复损坏。在这种情况下,我们从未进行过重新验证(因为如果您只是重新验证损坏(如果 etag 部分正确),那么您只需进行完全的无条件重新加载),因此其行为保持不变。

      2017年1月27日 上午04:48

  7. Sjon Hortensius

    您能否解释一下与现有的 `Cache-Control: public`(不带 must-revalidate)相比有什么区别?在我看来,如果结合较高的 max-age,效果应该是一样的。

    2017年1月27日 上午00:34

    1. Patrick McManus

      核心概念是,如果没有 immutable,新鲜和当前的概念就没有明确区分。HTTP 缓存允许使用不是资源最新表示的新鲜(即缓存可重播)数据——当然,Firefox 通常会使用它。但是,当您按下刷新时,我们过去会重新验证即使是新鲜的内容(例如,具有较高的 max age),以检查它们是否仍然是最新的。immutable 让缓存知道该资源永远只有一个版本,因此我们只需要担心新鲜度,并且在这种情况下永远不会重新验证。

      2017年1月27日 上午04:47

      1. Maarten Scholder

        但是,例如,1 年的 max-age 应该足够接近 immutable。没有哪个理智的网站会将其用于实际上会更改的资源。

        想象一下,支持部门将如何解释网站看起来很乱,但您希望它最多在 1 年内修复。或者想想您作为开发人员如何向您自己的支持团队解释它。或者如果在那一年内进行了其他更改会发生什么……等等。

        Immutable 是明确的,这有一些优点,但没有模糊魔法启发式的长时间 max-age 已经可以解决问题了。Immutable 看起来像 KISS,但如果只是尊重 max-age,会不会更简单?此外,更少的随机代码。

        2017年1月27日 上午05:23

      2. Gerd Neumann

        > 但是,当您按下刷新时,我们过去会重新验证即使是新鲜的内容(例如,具有较高的 max age),以检查它们是否仍然是最新的。

        为什么?这也是 Jeremie 在上面提出的观点。如果存在一个 `Cache-Control: public`(不带 must-revalidate)但具有高 max-age,则 Firefox 不应该再次检查。(严肃的问题,因为我一直都是这样配置我的服务器的)

        2017年1月27日 上午05:42

  8. Anchal

    您好,Patrick,
    写得非常好。您的文章解释了使用不变缓存来改进网页重新加载时间的好处。您能否也帮我理解如何在代码库中实现这一点?

    感谢您的任何帮助。

    此致,
    Anchal

    2017年1月27日 上午00:49

  9. Justin Avery

    Mozilla 做得令人惊叹!我们越能加快 Web 速度越好。

    出于好奇,您是否知道任何介绍实现 immutable 所需方法的文章?我也无法理解“immutable”和“永不改变”的确切含义……是否完全按字面意思理解?

    CSS 和 JS 永远不会改变,除非它们需要改变。此时,我们能否通过 styles.css?v=0.1 -> styles.css?v=0.2 来重新验证?或者是否需要 styles0.1.css -> styles0.2.css 来刷新文件(或者这完全取决于服务器设置?)

    感谢您耐心解答这些基本问题,但我希望确保我理解了这种方法的全部影响。

    2017年1月27日 上午01:59

    1. Patrick McManus

      查询字符串的更改应该足以在缓存中拥有一个新的 URL 密钥

      2017年1月27日 上午04:44

  10. Jason Grigsby

    与旧的 YSlow 指南(设置遥远将来的过期时间)相比,这样做有什么优势?

    如果您将遥远将来的过期时间设置为未来 50 年,那么设置 Cache Control: Immutable 是否会带来任何额外的好处?

    2017年1月30日 上午10:49

    1. Jason Grigsby

      我的同事指出我错过了上面回答这个问题的评论。这是我应该阅读评论的一次。对于重复提问,我表示歉意。

      2017年1月30日 下午12:32

  11. Wellington Torrejais

    我对这个新选项感到兴奋。
    并渴望在下一次使用它。

    谢谢。

    2017年2月2日 下午15:16

  12. Tara Li

    所以——如果您的公司决定修饰网站的徽标,您*必须*为其提供一个新文件名,并在所有相关代码中进行相应的更改,而不是仅仅让它在缓存中正常超时?(说真的——1 年的缓存有效期消息?人们严重低估了互联网上事物的波动性……我看不到任何*好的*理由将缓存超时设置为超过一个月……)

    2017年2月4日 上午10:40

    1. Jeremie M

      @Tara:这意味着如果您的公司无法跟踪其资源以更新它们,并且您关心及时更新它们,那么您不应该使用旨在用于缓存的标头。

      您最好只使用 etag,它根据内容而不是时间戳提供重新验证。

      这里我们讨论的是如何改进缓存,针对那些正确跟踪其资源的网站。而旧标志的问题在于,开发人员滥用了它们,导致这些标志现在被忽略,因此有了这个新的“又一个缓存”标志 :)

      2017年2月5日 10:49

      1. Tara Li

        那么,在当前这个被滥用和忽略的头部之后,下一个头部计划是什么?

        2017年2月18日 10:49

        1. Patrick McManus

          恕我直言,我认为这与旧属性被忽略无关。它们始终无法区分新鲜和当前——immutable允许这样做。

          2017年2月18日 14:21

  13. Ryan

    为什么这仅适用于https,而不适用于http?

    2017年2月6日 13:25

  14. Cory

    对于那些文件名中包含唯一哈希值且使用1年max-age的资源,添加immutable缓存头部有什么好处吗?

    在我工作的应用程序中,所有资源都经过哈希处理,并且哈希值包含在文件名中。当请求时,响应始终为200,并从缓存中提供服务。immutable缓存头部会进一步改进这一点吗?还是旨在优化具有静态文件名和低max-age值的静态资源?

    2017年2月7日 16:57

    1. Patrick McManus

      是的——immutable允许你区分仅仅是新鲜的(max-age)和新鲜且当前的(max-age加上immutable)。如果资源被认为是当前的,则无需在重新加载时重新验证它。

      请注意,重新加载(重新加载图标或Shift+R)与简单地重复使用不同——后者只需新鲜即可。这完全是关于显式重新加载。

      2017年2月8日 05:22

      1. Cory

        啊,知道了。感谢您的快速回复。

        我想知道这是否可以帮助加快我们的自动化测试,通过更快地提供内容。我不确定Selenium的每次测试之间进行哪种刷新。

        2017年2月8日 08:13

  15. Yo

    在我看来,从“隐私”的角度来看,与Facebook合作这些天似乎不是一件好事。它变得太流行了,Firefox似乎也开始变得太流行了。但我希望我错了。

    2017年2月8日 12:34

本文评论已关闭。