一、Gzip 的定义与压缩机制
Gzip 是一种通用的无损数据压缩格式,定义于 RFC 1952,广泛应用于文件存储和 HTTP 响应压缩。所谓无损压缩,是指数据经过压缩和解压缩后,可以恢复与原始内容完全一致的字节序列,不会改变文本、JSON 或其他数据的实际内容。

在 HTTP 应用中,Gzip 主要用于减少响应体需要传输的数据量。对于包含大量重复字段、固定格式和文本内容的 JSON、HTML、CSS 等资源,压缩通常能够有效减小传输体积,降低网络带宽消耗。
1.1 Gzip 内部怎样压缩数据
Gzip 使用的核心压缩算法是 DEFLATE。DEFLATE 主要结合了 LZ77 重复内容匹配 和 Huffman 编码两种技术。
LZ77 会在已经处理过的数据中寻找重复内容。当某段字节序列再次出现时,可以通过引用此前内容的位置和长度来表示,减少重复存储。Huffman 编码则根据符号的出现频率,为不同符号分配长度不同的编码,使较常见的符号通常能够使用更短的编码表示。
Gzip 在压缩数据外还包含必要的格式信息,例如文件头、校验数据等,用于标识压缩格式以及检查解压后的数据完整性。
因此,Gzip 对重复较多的文本通常效果较好,而 JPEG、PNG 等已经压缩过的数据通常很难进一步获得明显收益。压缩率还取决于原始内容的长度、重复程度和压缩级别。
二、HTTP 如何协商 Gzip 压缩
HTTP 压缩涉及客户端与服务器之间的内容编码协商。根据 RFC 9110,客户端使用 Accept-Encoding 表示自己能够接受的内容编码方式,服务端使用 Content-Encoding 说明响应内容实际采用了什么编码。
典型请求与响应可以表示为:
GET /api/data HTTP/1.1
Host: example.com
Accept-Encoding: gzip, br
HTTP/1.1 200 OK
Content-Type: application/json
Content-Encoding: gzip
Vary: Accept-Encoding
这里 Accept-Encoding 表示客户端支持的压缩方式,Content-Encoding: gzip 表示服务端返回的是经过 Gzip 编码的响应体。客户端接收到数据以后,通常由浏览器或 HTTP 客户端库自动解压,再交给上层程序处理。
Vary: Accept-Encoding 则用于告知缓存系统:响应内容可能根据客户端支持的编码方式发生变化。共享缓存需要据此正确区分响应变体,避免将不适合某个客户端的编码内容错误复用。
需要区分 Content-Encoding 与 Transfer-Encoding。前者描述响应内容本身采用的编码方式,例如 Gzip;后者涉及 HTTP 消息传输时的编码或分帧机制。Gzip 可以与 HTTP 的流式传输共同使用,两者处于不同的处理层次。
三、Gzip 为什么可能提高系统性能
Gzip 的直接作用是减少网络传输字节数,系统性能是否改善,还需要考虑压缩、传输和解压缩三个阶段。
一次接口请求的总耗时通常由业务计算、数据序列化、响应压缩、网络传输、客户端解压等多个部分组成。如果响应体很大,而且公网带宽或网络传输时间占比较高,Gzip 可以通过减少数据量降低传输耗时。
但压缩需要消耗 CPU 资源。压缩级别越高,通常越可能获得较好的压缩率,同时需要承担更多计算成本。因此,Gzip 的效果取决于当前系统的瓶颈。
| 系统情况 | Gzip 的可能效果 |
|---|---|
| 大型 JSON、HTML 响应 | 通常具有较好的压缩空间 |
| 公网带宽受限 | 可能显著减少传输耗时 |
| 小型响应体 | 压缩收益可能不足以抵消开销 |
| 服务器 CPU 已经饱和 | 可能进一步增加 CPU 压力 |
| 已压缩的图片或文件 | 通常收益有限 |
这一点对性能压测尤其重要。Gzip 能够降低传输数据量,但不能据此直接认定数据库查询更快、CPU 使用更少或接口 RPS 一定提高。 如果系统瓶颈主要来自数据库查询或模型推理,响应压缩对这些阶段的执行时间没有直接改善作用。
因此,评估 Gzip 应同时观察响应体积、端到端耗时、服务器 CPU、吞吐量和 P95 延迟,分析压缩收益来自哪个阶段。
四、Spring Boot 与 Nginx 的压缩配置
Spring Boot 提供了 HTTP 响应压缩配置,可以在 application.yml 中启用:
server:
compression:
enabled: true
min-response-size: 2KB
mime-types:
- application/json
- text/html
- text/plain
其中,enabled 控制是否启用响应压缩,min-response-size 设置参与压缩的响应大小条件,mime-types 指定允许压缩的媒体类型。Spring Boot 官方文档中默认的最小响应大小为 2 KB,实际是否压缩还取决于客户端协商、响应类型及服务器实现等条件。
如果应用通过 Nginx 对外提供服务,也可以在代理层配置 Gzip:
gzip on;
gzip_min_length 2048;
gzip_types application/json text/plain;
gzip_vary on;
上述配置是简化示例,需放在适当的 Nginx 配置上下文中。gzip_min_length 根据响应的 Content-Length 判断大小条件,gzip_types 配置额外的压缩媒体类型,gzip_vary 用于控制相关的 Vary 响应头。
当 Spring Boot 和 Nginx 同时具备压缩能力时,需要确定实际由哪一层完成压缩,避免重复配置和不必要的数据处理。对于已经带有 Content-Encoding 的响应,还需要保证代理正确处理编码信息。
4.1 Gzip 与 SSE 流式输出
Gzip 应用于 SSE 时,需要特别关注实时性。SSE 依赖事件逐步到达客户端,而压缩器和反向代理可能为了提高压缩效率暂时缓存数据。
如果数据积累到一定大小后才输出,就可能使客户端一次收到多个事件,导致流式显示延迟。对于 Token 级持续输出的应用,这种问题会直接影响交互体验。
因此,SSE 接口需要单独测试压缩与代理缓冲策略,必要时禁用特定响应的压缩或调整刷新机制。不能仅根据服务端已经调用发送方法,就认定数据已经及时到达浏览器。
五、压缩效果验证与面试理解
验证 Gzip 时,首先应检查实际 HTTP 响应是否包含 Content-Encoding: gzip,再比较启用前后的传输字节数、响应耗时与服务器 CPU 消耗。
可以使用以下命令检查响应头:
curl -sS \
-H "Accept-Encoding: gzip" \
-D - \
-o /dev/null \
https://example.com/api/data
这里的地址为公开示例地址,实际测试时替换为自己的接口。测试时应保持请求内容、返回数据规模和服务器负载尽量一致,并分别观察压缩与未压缩版本。对连续流式响应,还应单独测量事件到达间隔及首段数据延迟。
面试中可以这样理解:Gzip 是一种基于 DEFLATE 的无损压缩格式,通过重复内容匹配和编码优化减少数据体积。HTTP 通过 Accept-Encoding 和 Content-Encoding 协商压缩方式。它适合大型文本和 JSON 响应,主要改善网络传输开销;实际收益取决于响应可压缩程度、服务器 CPU 与网络瓶颈。对于 SSE,还需要考虑压缩缓冲对实时性的影响。
参考资料: RFC 1952《GZIP File Format Specification》;RFC 9110《HTTP Semantics》;Spring Boot《Embedded Web Servers》;Nginx《ngx_http_gzip_module》。