你曾经使用或至少理解服务器压缩的概念,这很可能很有用。通过在将服务器上的网站资产转移到浏览器之前对其进行压缩,我们已经能够实现显着的性能提升。
请求标头中的br
令牌Accept-Encoding
,如Google Chrome中所示
如果您通过HTTP访问非安全网站并查看任何资产的相同请求标头的值,您将看到该br
标记不存在。
我相信你现在已经受够了炒作,并准备好让你的手弄脏Brotli。因此,让我们开始使用Express框架在Node.js中编写一个小型Web服务器,并使用该shrink-ray
软件包实现Brotli 。
在Node.js中构建一个支持Brotli的Web服务器
将Brotli添加到现有的Web服务器(如Nginx或Apache)可能会很不方便,具体取决于您对它们的熟悉程度。对于Nginx,确实存在 Brotli模块,Apache也是如此,但构建和运行Apache模块需要一些技术诀窍。如果你对这种东西很酷,那很好,但是我们大多数人只是想安装一些东西并且正确地进行修补!
因此,为了让自己更容易一些,我将向您展示如何使用Node.js和Express设置一个用JavaScript编写的小型Brotli服务器。即使您从未使用过这些技术,也不必担心。在开始之前您需要的只是安装Node.js的副本; 你将被引导整个过程。在您了解它之前,您将在本地计算机上启动并运行Brotli支持的Web服务器,以备您仔细检查。
安装先决条件
因为我们的测试服务器是HTTPS,所以我们需要有一个证书和密钥。生成这些可能是一件苦差事。为了简化操作,您可以使用以下方法克隆我们需要的证书和目录结构git
:
git clone https://github.com/malchata/brotli-server.git
这将下载一个GitHub存储库,其中包含crt
目录中的证书和密钥文件,以及一个空的Web根目录htdocs
。您可以通过键入进入存储库目录cd brotli-server
。
(想要跳过去?如果您对从头开始编写Web服务器代码并且想要正确使用Brotli非常感兴趣,可以通过键入切换到包含已完成代码的分支来跳过git checkout -f brotli-server
。)
为了使服务器正常工作,我们需要使用npm安装一些软件包:
npm install express https shrink-ray
这将安装三个包:
express
是Express框架包。这用于启动一个简单的静态Web服务器,该服务器将提供htdocs
目录中的内容。https
是使我们能够通过HTTPS提供文件的软件包。shrink-ray
是压缩中间件,包含我们要测试的Brotli功能。它还包括gzip功能。注意:如果您在Windows上执行所有这些操作,则此程序包依赖于node-gyp,这对Windows用户来说可能会有问题。如果您有一个Linux子系统,例如Windows 10上可用的Linux子系统,那么您将获得更好的运气。如果您在Windows上开发Node,您可能会发现这些特性。如果没有,请阅读关于该主题的Github要点中的此评论。
安装这些依赖项可能需要一分钟。一旦完成,您就可以编写Web服务器代码了!
编写WEB服务器代码
在您选择的文本编辑器中,创建一个名为的新JavaScript文件https.js
,并从以下代码开始:
var express = require(“express”), // Imports the express package
https = require(“https”), // Imports the https package
shrinkRay = require(“shrink-ray”), // Imports the compression middleware
fs = require(“fs”), // The file system module for reading files (part of Node.js core)
path = require(“path”), // The path module for working with files and directory paths (also part of Node.js core)
app = express(), // An Express instance
pubDir = “./htdocs”; // The web root directory
如果您对Node.js不熟悉,该require
方法会导入我们需要在当前脚本中使用的模块。pubDir
变量是我们用来引用htdocs
目录的变量,我们将从中提供文件。
继续,我们需要shrink-ray
通过告诉app
对象中的Express实例来使用它来从包中设置压缩中间件。我们还将指示我们的Express实例静态地提供htdocs
目录中的文件:
app.use(shrinkRay()); // Tell Express to use the shrink-ray compression middleware
app.use(express.static(path.join(__dirname, pubDir))); // Tell Express to serve static files from the htdocs directory
我们将通过设置我们的HTTPS服务器并在端口8443上运行它来做到最好:
https.createServer({ // Creates an instance of an HTTPS sever
key: fs.readFileSync(“crt/localhost.key”), // Reads in the key file
cert: fs.readFileSync(“crt/localhost.crt”) // Reads in the SSL certificate
}, app).listen(8443); // Passes in our Express instance and instructs the server to run on port 8443
现在,当我们运行我们的Brotli驱动的Web服务器时:
node https.js
如果一切顺利,则不会发生任何错误,服务器将启动。要测试它,请将浏览器指向https:// localhost:8443 / readme.txt,您应该会看到一条短消息。如果你已经达到这一点,那么你已经准备好验证Brotli是否正常工作。
你怎么知道BROTLI在工作?
默认情况下,shrink-ray
如果请求的浏览器支持Brodli,并且服务器在HTTPS上运行,则会使用Brotli压缩内容。检查支持的最简单方法是获取JavaScript库的副本(例如React)并将其保存在htdocs
目录中。
从这里,打开Chrome或Firefox并启动开发人员工具。您可以通过按F12
Windows计算机或Command Alt I
Mac 来执行此操作。工具打开后,单击“网络”选项卡。“网络”标签是Chrome和Firefox开发人员工具中提供的常用工具,可显示给定网页的所有网络请求。打开此选项卡,导航到您在htdocs
本地Web服务器上的文件夹中保存的资产。您将看到网络实用程序填充了所请求的资源。
在Chrome中,我们可以Content-Encoding
在网络实用程序的“内容编码”列中看到资产标题的值。如果此列不可见,只需右键单击列标题,然后从显示的菜单中选择它。如果Brotli正在运行,您应该br
在“Content-Encoding”列中看到一个类似于下图所示的标记:
现在我们已经验证了Brotli在我们的本地测试Web服务器上运行,让我们看看Brotli与gzip相比的表现如何!
评估Brotli的表现
现在问题了:与gzip相比,Brotli的表现如何?如果您不想进行大量测试,那么可以通过性能测试对Brotli的性能进行全面了解。该测试设置为从文本文件中指定的热门网站下载资产,一旦收集资产,测试过程就会开始,如GitHub存储库README
文档中所指定:
- 将文件内容读入内存。
- 记下时间戳以标记测试的开始。
- 使用Brotli级别1压缩文件100次。
- 用时间戳标记测试结束。
- 记录压缩文件大小和压缩速度(以MB /秒为单位)。
- 对Brotli级别2到11重复步骤2到5。
- 对Gzip级别6重复步骤2到5。
- 以JSON格式输出结果。
基准测试文本文件中指定的网站数量巨大,因此测试需要很长时间才能完成。为了节省时间,我指定了我经常访问的20个网站(包括这个网站),并在其上运行基准测试。我觉得,与默认的gzip设置相比,这仍然可以提供Brotli在所有压缩级别上的性能的高级视图6
。所有Brotli设置与默认gzip设置的平均压缩速度如下表所示:
算法 | 压缩级别 | 速度(每秒MB) |
---|---|---|
gzip的 | 6 | 11.8 |
Brotli | 1 | 41.5 |
Brotli | 2 | 16 |
Brotli | 3 | 13.6 |
Brotli | 4 | 6.83 |
Brotli | 五 | 5.98 |
Brotli | 6 | 5.8 |
Brotli | 7 | 0.966 |
Brotli | 8 | 0.758 |
Brotli | 9 | 0.555 |
Brotli | 10 | 0.119 |
Brotli | 11 | 0.121 |
如上所述,这是一个非常高级的概述。该测试收集了大量数据,但平均压缩速度为我们提供了Brotli如何与gzip默认压缩级别进行比较的基本概念。这个测试的一个缺陷是,它不收集的数据都从gzip的设置1
来9
。它也无法真正量化Brotli如何影响网站加载时间,因为该测试可测量磁盘上已有文件的压缩性能。尽管如此,这个概述在某种程度上可以说明您将在以下测试中看到的内容,因为更高的压缩设置将是最慢的。我们只需要看看它如何影响网站加载时间以及它与所有可用的gzip设置的比较。
为了填补空白,我已经完成了一些自己的性能测试。首先,我们将了解所有 Brotli压缩设置与单个资产的所有 gzip设置的对比情况。然后,对于运行在使用Chrome的网络限制实用程序进行带宽限制的本地计算机上运行的Node.js驱动的网站,我们也会这样做。然后,我们将再次执行相同的操作,但是对于使用mod_brotli
压缩模块的Apache驱动的网站。
测试方法
在测试时,我想选择一个受欢迎且非常大的JavaScript库。React完全符合要求,以144千字节缩小。这似乎是比较单个文件的压缩算法性能的合理测试主题。
在比较压缩算法时,我们还想了解压缩资产的最终大小。虽然这个维度与页面加载时间紧密相关,但重要的是要注意它在每个场景中都不是一致的关系。压缩内容会占用CPU时间,如果算法太CPU密集,如果算法花费太长时间来完成其工作,则压缩比的任何增益都有可能无效。因此,我们想知道两个维度:最终文件大小和压缩资产加载所需的时间。
然而,简单地比较gzip和Brotli是不够的。我们可以调整这两种技术的设置,当我们这样做时,我们会影响它们的性能。gzip允许我们指定0
和之间的压缩级别9
,0
完全关闭压缩。Brotli可以类似地设置在1
和之间11
。gzip的默认值是6
,并且shrink-ray
包为Brotli设置的默认值是4
。我们可以像这样设置Brotli的压缩级别:
app.use(shrinkRay({
brotli: {
quality: 11 // Compression level configurable from 1 to 11
}
}));
下表是在Brotli和gzip的所有可配置级别压缩所选JavaScript库时的最终文件大小的综合集合。数字以千字节为单位,最小的文件大小以下划线和粗体显示。
水平 | gzip(KB) | Brotli(KB) |
---|---|---|
1 | 50.4 | 48.6 |
2 | 48.6 | 44.8 |
3 | 47.4 | 44.1 |
4 | 44.5 | 42.9 |
五 | 43.2 | 40.2 |
6 | 42.8 | 39.8 |
7 | 42.7 | 39.5 |
8 | 42.6 | 39.4 |
9 | 42.6 | 39.3 |
10 | N / A | 36.8 |
11 | N / A | 36.2 |
乍一看,我们可以看到收益令人印象深刻。在最高压缩级别,Brotli超过gzip 6.4千字节,这是不小的数据。如前所述,当压缩水平足够高时,可能会发生权衡。让我们看看各种压缩级别的加载时间是如何受到影响的:
水平 | gzip(毫秒) | Brotli(毫秒) |
---|---|---|
1 | 640.6 | 623.8 |
2 | 626 | 577.8 |
3 | 610.2 | 578.2 |
4 | 578 | 563.2 |
五 | 568 | 534.8 |
6 | 564.6 | 532 |
7 | 569.2 | 514.4 |
8 | 567.4 | 514 |
9 | 563 | 517.2 |
10 | N / A | 558.8 |
11 | N / A | 704.6 |
由于测试服务器在本地运行,因此我使用网络限制实用程序中的“常规3G”配置文件在Chrome中运行测试,以模拟通过慢速移动连接的加载时间。每个数字是五次试运行的平均值。
在可以进行直接比较的情况下,Brotli在文件大小的产量和加载时间方面似乎表现更好。一旦我们打的压缩级别10
和11
,但是,我们开始看到巨大的收益递减。即使这些压缩级别产生的文件大小要小得多,但计算开销会消除文件大小所带来的收益。
该shrink-ray
包使用缓存机制以自己的方式弥补了这种开销。在这些测试中,禁用了缓存机制,以便通过即时压缩准确了解Brotli的性能。默认行为shrink-ray
是首先以默认质量设置压缩响应。发生这种情况时,同一资产将以最高质量设置进行异步压缩,然后缓存以用于后续请求。
这种缓存机制为React库提供了大约480毫秒的加载时间。请注意,这种缓存功能并不是Brotli的标准配置,而是shrink-ray
设计如何工作。任何实现Brotli的模块可能会也可能不会缓存最近压缩的资产的条目。
真实场景中的性能
所有这些似乎都是临床的,因为我们实际上并没有将它应用于真实的网站,而是应用于单个文件。为了了解真实世界的表现,我拿了一个客户的网站,并通过我本地计算机上的绞拧器运行它。我在Brotli的不同质量级别上测试了加载时间,并禁用了缓存,然后启用了压缩缓存,以查看shrink-ray
程序包在放置到自己的设备时的性能。下面是使用前面概述的相同方法比较加载时间:
水平 | gzip(毫秒) | Brotli(毫秒) |
---|---|---|
1 | 871.4 | 869.2 |
2 | 869.2 | 848.4 |
3 | 868 | 858.4 |
4 | 845 | 850.2 |
五 | 850.8 | 857.8 |
6 | 852.8 | 844.8 |
7 | 867.8 | 846.4 |
8 | 860.4 | 833.8 |
9 | 847.8 | 832.6 |
10 | N / A | 825.2 |
11 | N / A | 849 |
11(缓存) | N / A | 823.2 |
在这种情况下,我们可以在最高gzip设置下获取一个52.4 KB的网站9
,并使用Brotli的最高设置将其有效负载减少到48.4 KB 11
。这减少了大约8%,并且在缓存生效后,我们可以进一步减少加载时间。请记住,这个例子是一个小网站。你的旅费可能会改变。这并不是说有效载荷较大的网站不会有任何好处,只是在完全为您的网站实施Brotli之前应该进行自己的分析。
我们可以看到的另一个场景是在Apache服务器上运行的WordPress博客。Legendary Tones是我托管给朋友的网站。虽然mod_brotli
Apache 的模块还处于初期阶段,但它运行良好,我们可以用它进行测试。我拉下来的网站,并运行它在我的本地Apache服务器上,我测试了两个所有可用设置mod_deflate
和mod_brotli
。此测试的条件与之前相同:使用Chrome的限制实用程序在“常规3G”设置下限制带宽,但是我执行了20次,而不是5次尝试。
水平 | gzip(毫秒) | Brotli(毫秒) |
---|---|---|
1 | 3060 | 3064 |
2 | 2968 | 2980 |
3 | 3004 | 2914 |
4 | 2900 | 2894 |
五 | 2910 | 2772 |
6 | 2858 | 2758 |
7 | 2836 | 2806 |
8 | 2854 | 2896 |
9 | 2998 | 2990 |
10 | N / A | 2910 |
11 | N / A | 2766 |
在可以进行直接比较的大多数情况下,Brotli似乎优于gzip,即使只是一点点。但是,让我们检查一下我们所做的所有测试的一些注意事项:
- 这些测试是在本地Web服务器上完成的,该服务器的唯一流量是我。
- 虽然Brotli收益率最高的压缩级别显著降低文件大小,这些资产的装载时间通常倾向于在遭受
10
和11
质量设置。 - 如果我们可以提前缓存压缩响应,我们可以否定较高的Brotli压缩级别的处理时间。
shrink-ray
这是为我们自动执行此操作,但其他实现可能缺少此缓存机制。
如果您愿意为您的项目测试Brotli,您将更好地了解它是否适合。好消息是,如果你正确地设置了你的网络服务器,那些不支持Brotli的浏览器将会回归到gzip,这意味着无论支持哪种算法,每个人都会获得一些好处。例如,这里是从线我的网站上同时实现的Apache配置mod_brotli
和mod_deflate
:
AddOutputFilterByType BROTLI;DEFLATE text/html text/css application/javascript text/javascript image/svg xml text/plain text/xml application/x-javascript
该配置指令的关键部分是该BROTLI;DEFLATE
部分。当加载mod_brotli
和mod_deflate
模块时,我们可以指定首选的压缩算法。通过BROTLI
首先放入链中,支持它的浏览器将接收由其压缩的内容。如果浏览器出现不支持Brotli,它将由gzip(DEFLATE
)提供。
随着我们的时间一起走到尽头,让我们花一点时间来介绍一下我们对Brotli的了解。
结论
我此时的调查结果告诉我,你有充分的理由做一些研究,看看Brotli在你的网站上有什么可能。在大多数情况下,Brotli似乎可以从您的网站中获得更多性能,这可能值得追求。
虽然Brotli在较高的压缩水平下开始变得迟钝,但是达到良好的平衡可以提供一定程度的好处。关于什么压缩设置对所有网站都有好处,我无法概括。你只需要自己测试一下。我强烈建议您使用此方法查看结果,并查看服务器的实现情况。如果你使用Node.js,Nginx或Apache提供页面,你就有了选择。
此外,值得注意的是,Brotli是一个不断发展的项目。谷歌的GitHub项目存储库显示了定期的贡献,这足以让具有表现意识的网络开发人员密切关注这一有前途的新技术。