3. Brotli实战:Brotli vs Gzip性能对比、浏览器兼容性、服务端配置、预压缩策略
聊到资源压缩,很多人第一反应就是 Gzip。确实,Gzip 统治了 Web 压缩领域快二十年。但今天我要跟你聊聊它的继任者——Brotli。说实话,我第一次接触 Brotli 是在 Google 的某次技术分享上,当时觉得这名字挺怪,试过之后才发现,这玩意儿是真能打。
一句话总结:Brotli 不是 Gzip 的替代品,而是 Gzip 的进化版。它用更复杂的算法,换来了更高的压缩率。
3.1 Brotli vs Gzip:到底差在哪?
先看一组我实际项目中的压测数据。一个 300KB 的 jQuery 库,Gzip 压缩后大概 100KB,Brotli 能压到 85KB 左右。别小看这 15KB,在移动端弱网环境下,这就是 200ms 的差距。
| 对比维度 | Gzip | Brotli |
|---|---|---|
| 压缩算法 | Deflate (LZ77 + Huffman) | LZ77 + 上下文建模 + 熵编码 |
| 压缩比(文本) | 约 3:1 | 约 4:1 ~ 5:1 |
| 压缩速度 | 快(级别 6 约 50MB/s) | 慢(级别 11 约 5MB/s) |
| 解压速度 | 快(约 250MB/s) | 快(约 200MB/s) |
| 字典支持 | 无 | 内置静态字典(HTML/JS/CSS 专用) |
| 浏览器支持 | 所有浏览器 | Chrome/Firefox/Edge/Safari 11+ |
为什么会这样?Brotli 内置了一个针对 Web 资源的静态字典。你想想看,HTML 里的 <div>、<span>,JS 里的 function、return,这些高频词根本不需要重复编码。Gzip 是每次从头开始建字典,Brotli 直接拿现成的用。
我的建议:静态资源(JS/CSS/HTML)用 Brotli 级别 5-6 就够了。级别 11 压缩率只高 2-3%,但压缩时间翻了好几倍,不适合线上实时压缩。
3.2 浏览器兼容性:别踩坑
嗯,这里要注意。Brotli 虽然好,但不是所有浏览器都认。我去年帮一个客户做性能优化,全站上了 Brotli,结果发现他们的用户还有不少在用 Safari 10。那叫一个尴尬。
目前主流浏览器的支持情况:
- Chrome 49+:完全支持
- Firefox 44+:完全支持
- Edge 15+:完全支持
- Safari 11+:支持(但只支持 HTTPS)
- Opera 36+:完全支持
- IE 11:不支持
我曾经踩过的坑:Safari 在 HTTP 协议下不会发送 Accept-Encoding: br,只认 HTTPS。如果你还在用 HTTP,Brotli 对 Safari 用户就是白费功夫。
最佳实践是内容协商。服务端根据请求头 Accept-Encoding 决定返回哪种压缩格式:
# 请求头
Accept-Encoding: gzip, deflate, br
# 服务端响应
Content-Encoding: br
Content-Type: text/javascript
Vary: Accept-Encoding
注意那个 Vary 头。少了它,CDN 缓存可能会乱套。我见过一个案例,CDN 把 Brotli 版本缓存给了不支持 Brotli 的浏览器,结果页面直接白屏。
3.3 服务端配置:Nginx 实战
我个人习惯用 Nginx,配置起来最顺手。先确保你安装了 Brotli 模块:
# 编译安装
./configure --with-compat --add-module=/path/to/ngx_brotli
make && make install
# 或者用动态模块
load_module modules/ngx_http_brotli_filter_module.so;
load_module modules/ngx_http_brotli_static_module.so;
然后配置压缩规则:
http {
# 开启 Brotli
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/json application/javascript
application/xml application/xml+rss text/javascript
image/svg+xml application/vnd.ms-fontobject
application/x-font-ttf font/opentype;
# 保留 Gzip 作为降级
gzip on;
gzip_comp_level 5;
gzip_types text/plain text/css application/json application/javascript
application/xml application/xml+rss text/javascript;
# 重要:根据客户端能力选择
gzip_vary on;
brotli_vary on;
}
避坑指南:不要把 brotli_comp_level 设到 11。我在生产环境试过,CPU 直接飙到 80%,QPS 掉了一半。级别 6 是性价比最高的选择。
3.4 预压缩策略:让性能再飞一会儿
实时压缩虽然灵活,但每次请求都要算一遍,浪费 CPU。预压缩就是提前把文件压好,直接存两份——一份原文件,一份 .br 文件。
我常用的做法是在 CI/CD 流程里加一步:
# 使用 brotli 命令行工具
brotli -q 6 -i dist/app.js -o dist/app.js.br
brotli -q 6 -i dist/style.css -o dist/style.css.br
# 或者用 Node.js 脚本
const zlib = require('zlib');
const fs = require('fs');
const input = fs.readFileSync('dist/app.js');
const compressed = zlib.brotliCompressSync(input, {
params: {
[zlib.constants.BROTLI_PARAM_QUALITY]: 6
}
});
fs.writeFileSync('dist/app.js.br', compressed);
Nginx 静态模块会自动匹配:
location /static/ {
brotli_static on; # 优先使用 .br 文件
gzip_static on; # 降级使用 .gz 文件
expires 365d;
add_header Cache-Control "public, immutable";
}
这样配置后,Nginx 会先找 .br 文件,找不到再找 .gz,都没有才实时压缩。性能开销几乎为零。
核心收益:预压缩 + 静态模块,CPU 占用降低 90% 以上,响应时间稳定在 5ms 以内。我之前的项目从实时压缩切到预压缩后,服务器负载直接降了一半。
3.5 整体流程一览
下面这张图展示了 Brotli 从构建到交付的完整链路。我建议你对照着看,理解每一步的作用。
3.6 实战检查清单
最后,给你一份我每次上线 Brotli 都会过的检查清单:
- 确认浏览器覆盖:检查用户设备分布,Safari 11+ 和 Chrome 49+ 是底线
- 配置内容协商:Nginx 同时开启 brotli 和 gzip,用
Vary头区分 - 选择压缩级别:静态预压缩用级别 6,实时压缩用级别 4-5
- 验证 CDN 兼容:确保 CDN 支持 Brotli 透传,否则会二次压缩
- 监控 CPU 负载:上线后观察一周,确认没有异常飙升
- 测试降级路径:模拟不支持 Brotli 的浏览器,确认能回退到 Gzip
我曾经翻过车:有次上线忘了配 Vary: Accept-Encoding,CDN 把 Brotli 版本缓存给了所有用户。结果 IE 用户拿到乱码,线上事故持续了 20 分钟。从那以后,我每次上线前都会用 curl 手动验证响应头。
Brotli 不是银弹,但在文本压缩这个场景下,它确实比 Gzip 强一截。配置不复杂,收益却很实在。你想想看,同样的带宽,能多传 20% 的资源,何乐而不为?