网页加载速度慢?Brotli与Gzip压缩算法性能对比与配置

Brotli和Gzip是两种主流的HTTP压缩算法,但很多站点仅启用Gzip,错失了更优的压缩率和加载速度。本文从算法原理、压缩比与CPU开销两个维度对比两者的实际表现,并给出Nginx、Apache及CDN的完整配置方案,同时说明浏览器兼容性与回退策略。

网页加载速度慢?Brotli与Gzip压缩算法性能对比与配置
封面图:ZuCDN · ZuCDN 原创

从带宽瓶颈到压缩算法选择

网页加载缓慢的根因通常不是网速本身,而是传输的字节过多。开启HTTP压缩是成本最低的优化手段之一,但多数人只停留在“启用Gzip”这一步。2015年Google推出的Brotli算法在文本压缩率上全面超越Gzip,却因配置稍复杂而未被广泛采用。本文聚焦两类算法在真实场景下的差异,并给出可落地的配置步骤,不涉及空洞的理论推导。

Brotli与Gzip的核心差异

算法原理与适用场景

Gzip基于DEFLATE算法,对HTML、CSS、JS等静态资源压缩率通常在60%-70%左右。Brotli则采用LZ77 + 霍夫曼编码的升级版,并内置了预定义的静态字典(包含常见英文单词、HTML标签等)。这意味着Brotli在小文件(<10KB)上的压缩收益更明显——静态字典能直接命中高频片段,减少动态建模的额外计算。

另一个关键区别是压缩等级。Gzip的压缩等级范围1-9,Brotli的范围0-11。Brotli在等级4-6时即可达到Gzip等级9的压缩率,而CPU开销反而更低。当Brotli等级为11时,压缩率能再提升5%-10%,但压缩耗时可能增加数倍——这对实时压缩场景(如动态页面)不友好。

性能数据:压缩率与CPU开销

以一份150KB的未压缩HTML文件为例:Gzip等级6压缩后约45KB,Brotli等级6压缩后约38KB,节省额外15%的传输体积。对于JS/CSS文件差异略小(约8%-12%)。Brotli在压缩率上的优势源自其更长的滑动窗口(最大16MB vs Gzip的32KB)与更优的熵编码。

CPU开销方面,解压速度Brotli比Gzip慢约10%-20%(因为解码需要处理更大的窗口),但压缩速度差距更大。Brotli等级4的压缩速度与Gzip等级6相当,但压缩率更好。因此推荐对静态资源(如Webpack打包后的文件)预压缩(.br文件直接存储),避免每次请求时压缩;对动态响应则只启用Gzip或Brotli低等级。

配置指南:Nginx与Apache实战

Nginx:启用Brotli并设置降级

首先编译或安装ngx_brotli模块(可通过nginx官方模块或第三方仓库)。以下是最简配置:

brotli on;
brotli_comp_level 6;
brotli_static on;
brotli_types text/plain text/css application/javascript application/json image/svg+xml text/plain;
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css application/javascript application/json image/svg+xml;

brotli_static on 会让Nginx优先查找预先生成的“.br”文件,避免动态压缩。当客户端不支持Brotli时(检查Accept-Encoding头),Nginx自动回退到Gzip。这种双配置确保兼容性:旧版浏览器(如Safari 11之前)只能解压Gzip,而现代浏览器优先Brotli。

Apache:通过mod_brotli实现

Apache 2.4.26及以上版本可通过mod_brotli模块启用。配置示例:

LoadModule brotli_module modules/mod_brotli.so
<IfModule brotli_module>
    AddOutputFilterByType BROTLI text/html text/css application/javascript
    BrotliCompressionQuality 6
</IfModule>
<IfModule gzip_module>
    AddOutputFilterByType DEFLATE text/html text/css application/javascript
</IfModule>

注意Apache需要确保Brotli和Deflate(Gzip)同时生效,并利用Vary头告知代理缓存。但Apache的Brotli模块在动态压缩时CPU消耗较高,建议对静态资源使用预压缩。

CDN与反向代理中的陷阱

Cloudflare、Akamai等主流CDN现已原生支持Brotli,但部分自建反向代理(如Nginx作为反向代理去后端获取源站内容)需要特殊处理。如果源站后端只输出Gzip,反向代理无法直接转码为Brotli——除非用buffer并重新压缩(消耗额外CPU)。更优做法是后端只输出未压缩内容(或Brotli预压缩文件),让CDN/反向代理层根据客户端Accept-Encoding决策压缩算法。

验证与回滚:不盲目信任

配置完成后,通过curl测试:

curl -H "Accept-Encoding: br" -I https://example.com/style.css
# 响应头应包含Content-Encoding: br

curl -H "Accept-Encoding: gzip, deflate" -I https://example.com/style.css
# 响应头应包含Content-Encoding: gzip

同时检查压缩前后文件大小差异。若发现某些HTML页面正确返回但未压缩(Content-Encoding缺失),常见原因是后端动态内容被代理缓存时压缩策略冲突。解决办法是在源站设置无压缩输出,让代理层统一压缩。

如果启用Brotli后CPU飙升,可降低brotli_comp_level至4或只对静态预压缩文件使用Brotli。动态压缩建议等级不超过6,且通过监控工具(如Prometheus + nginx-exporter)观察worker进程CPU占比。

权衡:何时不该用Brotli

虽然Brotli综合表现优于Gzip,但以下场景建议谨慎:

  • 低频访问的小站点:预压缩文件可能增加存储开销(.br文件占磁盘约1.5倍原始大小),且日常访问量不足时收益微乎其微。
  • 硬实时动态接口:例如聊天应用或交易推送,Brotli的解压延迟(毫秒级)虽小,但对每个包独立压缩时CPU消耗可能累积。这类场景常用Zlib(Gzip)甚至不压缩。
  • 老旧浏览器仍占比高:部分企业内网用户仍使用IE11或Safari 10,这些浏览器不支持Brotli。务必配置Gzip回退。

总结:一步优化,长期受益

启用Brotli并非复杂转型,而是在现有Gzip基础上叠加一个Accept-Encoding的候选。静态预压缩 + 动态Gzip回退的组合既能获得最优压缩率,又不牺牲兼容性。实测典型站点开启Brotli后整体资源字节可减少10%-15%,尤其对移动端低速网络改善明显。唯一需要付出的成本是服务器模块编译与预压缩脚本的维护。相比更换协议或重写代码,这是性价比最高的性能优化之一。

延伸阅读