通过共享字典提高压缩效率

数据压缩是一项久经考验的性能优化技术,可缩减符合条件的网页资源的大小。在一段时间内,通常的做法是在网络服务器上主要使用 gzip 压缩常见的基于文本的网页资源(例如 HTML、CSS 和 JavaScript 文件),然后发送到客户端进行解压缩。这样可以缩短资源的加载时间,而不会影响网页的预期行为。

尽管 gzip 本身就已经非常有效了,但近年来,我们还是进一步改进了网络压缩。2016 年,Brotli 算法已在 Chrome 中推出,为符合条件的资源提供了更好的总体压缩比。到 2017 年底,所有现代浏览器都支持 Brotli,服务器也开始支持 Brotli。最近,Chrome 推出了 ZStandard 压缩功能

不过,工作并不能就此止步!Chrome 团队一直致力于在网络上提供共享字典,这些字典现已面向 Brotli 和 ZStandard 提供源试用。共享字典可以作为 Brotli 和 ZStandard 压缩的补充,从而为经常发布更新代码的网站提供显著更高的压缩比率,并且在某些情况下可以实现 90% 或更高的压缩比率。这篇博文详细介绍了共享字典的运作方式,以及如何注册源试用,以便在您的网站上将其用于 Brotli 和 ZStandard。

共享字典说明

压缩就是在输入中查找冗余序列,并使用该信息创建更小的输出(稍后可以逆转)的过程。压缩在 Web 上效果很好,因为它可以显著减少资源加载时间。Brotli 和 ZStandard 均可通过使用压缩字典进一步提高效果。压缩字典是这些算法可在压缩过程中使用的一组其他模式。事实上,Brotli 的高效率在一定程度上是通过使用内部字典实现的。

但是,用户精选的自定义字典可与包含特定资源专用模式的 Brotli 和 ZStandard 搭配使用。实际上,自定义字典是可应用于任何输入的外部文件。字典可以与应用的生产代码高度相关,也可以与任何实际内容密切相关。给定字典对其输入的适用程度将对整体压缩效率产生重大影响。与输入内容的内容高度相似的字典,与包含通用或不相似内容的字典相比,输出的压缩率更高。

下面的示例展示了自定义压缩字典的有效性:假设您的网站使用 Angular 框架,而您当前使用的版本是 1.7.9 版。此版本的 Angular 框架在未压缩时约为 172 KiB。使用 Brotli 的默认设置进行压缩时,其大小约为 53 KiB。这将产生近 70% 的压缩率。不过,如果您稍后决定升级到 Angular 1.8.3,由于此版本的 Angular 的大小与 1.7.9 版大致相同,因此压缩率会与上一版本大致相同。

这时,自定义字典就能派上用场了,我们需要使用名为“增量压缩”的过程,即可以使用先前版本的资源的字典来压缩后续版本。在前面的示例中,如果您使用版本 1.7.9 作为字典来压缩 Angular 1.8.3 的版本,则输出将超过 4 KiB。这意味着压缩率接近 98%。显然,压缩字典对加载性能有很大影响,其效果已经在实际应用中实现

但是,使此流程在网络上运行存在一个挑战。问题在于,如果您使用字典来压缩资源,则需要使用同一字典来解压缩。以前曾在网络上尝试执行此流程(即 SDCH),但安全实现并非易事。这一关于共享字典压缩的最新方案解决了这些问题,同时对静态和动态资源提供了巨大的优势。

Chrome 如何通告支持共享字典

所有浏览器都会通过 Accept-Encoding 请求标头公布其支持的压缩算法。标头内容是以英文逗号分隔的支持编码列表:

Accept-Encoding: gzip, br, zstd

这个特定的 Accept-Encoding 标头表明,请求资源的浏览器支持 gzip、Brotli 和 ZStandard 压缩算法。然后,响应请求的网络服务器就可以决定在响应请求时使用哪种算法。

启用共享字典支持后,如果资源有相关字典可用,则系统会向 Accept-Encoding 标头中添加额外的令牌。Brotli 的令牌为 br-d,Zstandard 的令牌为 zstd-d。Chrome 还会包含可用字典的哈希值(详见下文)。

Accept-Encoding: gzip, br, zstd, br-d, zstd-d
Available-Dictionary: :pZGm1Av0IEBKARczz7exkNYsZb8LzaMrV7J32a2fFG4=:

如果网络服务器已配置为识别此令牌,并且它能够识别字典,则可使用通过适用编码的字典压缩的资源来响应该请求。这实际上如何实现取决于请求是针对静态资源还是动态资源。

针对静态资源的共享字典压缩

静态网页资源是指始终针对所请求网址生成相同响应的资源。JavaScript 和 CSS 文件都是可压缩的静态网页资源的常见示例。这些资源通常会以某种方式进行版本控制,以达到缓存目的 - 有时会在文件名中包含文件内容的哈希值(例如 styles.abcd1234.css),或采用其他某种对资源进行指纹的方法。这些资源类型非常适合共享字典提供的增量压缩,因为静态资源通常会缓存很长时间,并且往往以一定的频率更新。

可以通过为静态资源设置 Use-As-Dictionary 响应标头来为其指定字典。标头采用几个键值对中的一个,但唯一必需的一个是 match,它接受 URLPattern 语法,用于指定应使用字典的资源路径:

Use-As-Dictionary: match="/dist/styles.*.css"

您可以将 Use-As-Dictionary 标头看作一种机制,该机制适用于与其中指定的模式匹配的资源的未来版本。假设您的网站在一个 CSS 文件中提供其所有样式。为简单起见,我们假设该资源的第一个版本位于 /dist/styles.v1.css,并且发送时具有一个包含 match 值为 /dist/styles.*.cssUse-As-Dictionary 响应标头。

一段时间后,您更新自己网站的 CSS 并发布新版本(位于 /dist/styles.v2.css)。由于上一版本的 Use-As-Dictionary 响应标头中使用的 match 值适用于此请求,因此浏览器将发送 Available-Dictionary 标头,其中包含编码为结构化字段字节序列的字典的哈希值:

Accept-Encoding: gzip, br, zstd, br-d, zstd-d
Available-Dictionary: :pZGm1Av0IEBKARczz7exkNYsZb8LzaMrV7J32a2fFG4=:

此时,由服务器来配置压缩,以确保使用匹配的字典。然后,系统会发送使用该字典压缩的资源,并使用用户浏览器缓存中的可用字典进行解压缩。

如果您经常为网站发布新代码,增量压缩将大有裨益。不过,流程灵活多变。如果浏览器无法确定在用户浏览器缓存中提供了字典,就不会Accept-Encoding 标头中指定额外的 br-dzstd-d 令牌。在这种情况下,应用标准压缩流。

针对动态资源的共享字典压缩

动态资源也可以受益于共享字典压缩。动态资源是指随环境而变化的资源,例如,主页会随着新闻事件而频繁更新的新闻网站。HTML 文档通常是动态资源。在这种情况下,字典可包含网站的大多数常用 HTML 结构和模板代码,这些模板代码将指向压缩页面(仅发送每个页面的唯一部分)。

由于动态生成的资源的性质,必须在客户端上加载字典以供日后使用。提前加载字典意味着对动态资源应用共享字典压缩属于推测性。这种情况下,我们希望您的网站能获得足够的流量,以便将字典费用摊销大量导航费用。如果您决定尝试一下,第一步是通过页面 HTML 中的 <link> 元素指定字典的位置:

<link rel="dictionary" href="/dictionary.dat">

当 Chrome 遇到此 <link> 元素时,可能会在页面处于空闲状态时以低优先级提取字典,以避免带宽争用。字典本身的响应必须指定 Use-As-Dictionary 标头,并指定其适用的动态资源路径:

Use-As-Dictionary: match="/product/*"

从此处开始,流程与静态资源流程大致相同。浏览器将看到该字典本身已应用于匹配的资源,并且会使用字典内容的哈希值向请求附加 Available-Dictionary 标头,这也类似于前面介绍的静态资源流。

在构建时压缩静态资源

如果您熟悉捆绑器,那么您可能会对它们熟悉的各种插件,它们可以在构建时压缩资源,然后提供这些压缩资源。例如,在收到请求时,Apache 允许您使用指令来处理这些预压缩资源

大多数支持压缩的基于 Node.js 的捆绑器都使用 Node 的内置 Zlib 库。Zlib 支持 Brotli,以及使用它的捆绑器。Zlib 通常提供将选项直接传递到 Zlib 的接口,Zlib 支持字典辅助压缩。以下是一些支持使用字典的捆绑器:

请注意,适用于资源任何给定版本的可用字典可以使用资源的任何先前版本之一。这意味着,您需要分析用户流量并制定相应计划。力求实现平衡,并尽可能开发使尽可能多的回访用户受益的资源。CDN 提供商目前正在实验共享字典压缩功能。尚无可供公开使用的实现方式,但我们预计这一点会做出改变!

试试看!

对于经常发布更新的生产代码并接收来自回访者的流量的网站,将共享字典压缩与浏览器现有的压缩功能集成有可能显著提高加载性能。如果您想尝试对共享字典进行压缩,有以下两种选择:

  1. 如果您只是要亲自尝试修改共享字典压缩,以了解其工作原理,则可以在 chrome://flags 页面上启用压缩字典传输实验性功能。
  2. 如果您有兴趣在自己的正式版网站上试用该功能,并了解共享字典压缩功能如何给真实用户带来便利,请注册源试用以获取令牌,并详细了解源试用的运作方式

总结

我们非常高兴看到 Web 压缩技术的重大进步,以及它使人们日常使用的现有应用的速度有多快。我们鼓励您试用一下此功能,最重要的是,如果您试用一下,我们非常希望了解您的想法!如果您发现错误,请在 crbug.com 上提交错误。如需其他资源和工具,请访问 use-as-dictionary.com。最后,如果您有兴趣更深入地了解它的运作方式,不妨查看铺垫消息