Gzip
Gzip 动态压缩及缺点
网站的 gzip 压缩介绍
客户机和服务器在 HTTP 协议上添加 request 的 header accept-encoding: gzip。
可以设置压缩等级,类似于 rar 和 zip 的压缩,等级越高文件越小。
解压缩对 cpu 的消耗对服务器很明显对客户端不明显,一般构建网站会配置 gzip 的。
随便找一个大网站,控制台看 200 响应码的数据包(不看 301 重定向)。

google 自己开发了 br 压缩算法,客户端 chrome 肯定支持,国内的基本都支持,国内好多都是基于 chrome 开发的。
参数配置
gzip on;
- 开启gzip
gzip_buffers 16 8k;
- 压缩的缓冲区大小
gzip_comp_level 6;
- 压缩级别可设置
1~9
gzip_http_version 1.1;
- 只对HTTP/1.1以上的请求启用压缩
gzip_min_length 1024;
- 只有响应体大于1024字节才压缩
gzip_proxied any;
- 对反向代理请求也启用压缩
此配置的参数如图,其中 off 和 any 是比较常见的。

可以看到只对反向代理服务器生效,而且是针对上游服务器返回的 header。
gzip_vary on;
- 在响应头加
Vary: Accept-Encoding(一般不配置的哦)
gzip_types text/plain text/css application/javascript application/json application/xml text/javascript;
- 针对特定MIME类型压缩

如图,建议多配置,因为少配了就不压缩的。
gzip_disable "MSIE [1-6]\.(?!.*SV1)";
不建议配置,有正则,会极大消耗性能,越复杂的正则越影响性能。
- 作用:禁用老版本 IE 浏览器的 gzip 压缩。
- 通俗理解:IE6 及以下版本有 bug,处理 gzip 会出问题。这个正则匹配到这些浏览器时,Nginx 就不返回压缩内容。
- 为什么保留:现在几乎没人用 IE6,但保留无害,可以不改。
在 /etc/nginx/nginx.conf 配置 gzip 全局生效后重启 nginx:
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
gzip_min_length 256;
# 其中好多都是nginx默认自带的,直接删去注释即可
# 配置参数的具体意思不用纠结
配置gzip前后test页面的控制台对比图

其中 transfer-encoding chunked 表示数据包拆成小块发送,最后发送的包为 0 字节表示所有的数据传输完毕,是 gzip 启用的标志。
显示 Content-Encoding: gzip 就认为 content-length 配置生效。
gzip_vary on; 一般是给老的浏览器配置的,只是多了一个字段而已。
控制台有一个 wifi 的图标,可以查看当前浏览器支持的压缩算法:

zstd 也是很好的算法只是老的浏览器不支持。
这里还有好多测试用的功能:

以上是动态压缩,请求到后端都会压缩,致命缺点就是无法使用 nginx 的高级特性 sendfile(针对本地磁盘文件,数据零拷贝,直接与内核交流找文件,不加载到 nginx 内存,直接通过网卡驱动传数据)。
但是还是期望使用 Gzip,且不放弃 sendfile,就需要静态 Gzip 压缩。
Gzip 静态压缩及扩展配置
编译安装
静态是动态的扩展功能,可以预先打包压缩包。
nginx 开启了静态压缩会优先读取 gz 文件。
在官方文档可以找到 gz 的相关配置。

可以看到静态 Gzip 配置说明了,不默认在预编译的包里,要手动加入。

但是默认安装的 nginx 是带有静态 Gzip 功能的。
nginx -V(大写) 可以看到版本和编译时配置的信息。
其中有 --with-http_gzip_static_module
编译过程
cd nginx-1.21.6 # 进入 Nginx 源码目录,必须在源码目录安装
ls # 看看里面有什么
./configure --prefix=/usr/local/nginx --with-http_gzip_static_module # 配置编译选项,指定安装路径,开启 gzip 静态模块
make # 编译(不安装)
systemctl stop nginx # 停掉旧 Nginx
cd objs/ # 进入编译输出目录
mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.old1 # 备份旧的可执行文件
cp nginx /usr/local/nginx/sbin/ # 把新编译的 nginx 替换过去
这是源码编译升级 Nginx 的流程,用新编译的 nginx 可执行文件替换旧的,然后重启就能用新功能。
其中 ./configure 是编译前的配置检查脚本。
配置选项说明
直接查看官方的文档:

中间的 Directives(命令)标题就是可配置的参数,只有 3 个配置选项。
gzip_static on/off/always; 作用域依然是 server、location、http 三个,也就是把它配置到和动态 Gzip 一个地方即可。
on检查客户端是否支持 Gzip,不支持就不发送 Gzip 包off直接关闭 static 整个模块- 不论是否支持 Gzip 都发送压缩包(客户端不支持就解不开压缩包)
- 对于上面一条的情况要用
ngx_http_gunzip_module配合解决问题(如果是编译安装的依旧不在预编译包中),作用是发给不支持 Gzip 的客户端之前解压压缩包再发

本机上有原文件和压缩包,有了这个之后可以把原文件都删掉,假设之前有 2w 个文件和 2w 个压缩包,用了 gunzip 就可以删掉原文件,无需读取原文件(因为支持 Gzip 的客户端需要保留压缩包,不支持的又配合 gunzip 变成也只需要压缩包,所以可以删除原文件)。
主要功能就是节约了磁盘空间。
虽然听起来很牛但是仅仅只是在特殊场景下才行,大多数都不去配置这个。
同样 --with-http_gunzip_module 模块是 gunzip 功能的编译模块,默认安装的 nginx 同样配置在 nginx.conf。
--with-http_gunzip_module 也在默认安装的编译模块中。
#动态Gzip配置
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
gzip_min_length 1024;
#静态Gzip配置及其扩展配置
gzip_static always;
gunzip on;
gunzip_buffers 32 4k;
gunzip on; 和 gzip_static on; 其实是冲突的,静态压缩指定了,先找压缩文件,然后找源文件,没有指定必须发送压缩文件,可以改为 always,即必须发送压缩包,此时配合 gunzip 一同配置才会生效。

此种方式无法得知文件的大小,即 content-length,因为传回的是解压后的文件,磁盘上只剩压缩包了自然无法返回文件的大小(服务器端帮客户端解压)。
由于返回的是后端的文件,所以如果做了动静分离就不需要请求后端文件,无法测试 gunzip 的功能了。
创建测试文件
mkdir -p /var/www/html/testgunzip
echo "gunzip works" | gzip > /var/www/html/testgunzip/index.html.gz
# 文件是root创建的,有root权限普通用户无法读取,需要修改一下
sudo chown -R www-data:www-data /var/www/html/testgunzip
sudo chmod -R 755 /var/www/html/testgunzip
# 然后在default下配置location块
location /testgunzip {
}

之后删除了测试文件,符合规范。
当 nginx 直接作为 CDN 存储数据服务器的时候可以只开静态的 gzip,本地原文件可以删除,把解压缩的压力丢给客户端。一些高频访问的页面也可以用 static 压缩,可以把 static 看作是动态的一种扩展(不建议对二进制、音频、视频做 gzip 压缩,因为本来就是“压缩”的形式了)。
访问一个网站,看他控制台同时有 gzip 和 content-length 就说明他用了静态 gzip。
因为动态压缩边压边发不知道总文件大小,静态才知道(一些大网站的会这样配置,好处就是加载快),当然一些文本文件适合,但是不是所有文件类型,配置方式就是把 /var/www/ 下的网站资源全都搞成压缩包的形式:

这样修改的时候需要解压缩很麻烦,所以可以这样:
进入当前目录 gunzip -r ./ 直接回来了都。
为了避免 sendfile 失效需要去配置静态的 gzip(一般权限都在架构师和项目总监上)。
Brotli
安装(太耗时了且需求不大,不演示了直接贴图)
brotli 是谷歌原创的,很多站点都会使用,默认是 https 协议,之后也支持了 http。
算法的效率很高,因为其中字典很多,对文本文档效率显著。此配置是可以和原有的 gzip 配置共存,也可以看作是一个扩展。浏览器一般优先 brotli 后使用 gzip。
由于编译方式不适用于我的 nginx 此处仅用视频实操做演示。


brotli 不能和 gunzip 共存,可以注释掉 gunzip。
使用参数
配置和 gzip 基本是一样的。
官方文档:https://github.com/google/ngx_brotli

brotli on;
brotli_static on;
brotli_comp_level 6;
brotli_buffers 16 8k;
brotli_min_length 20;
brotli_types text/plain text/css text/javascript application/javascript text/xml application/xml application/xml+rss application/json image/jpeg image/gif image/png;
brotli_static on | off | always; 同样支持预先压缩,变成 .br 文件,先找压缩包后找原始文件。
brotli on | off
brotli_types 对文档类的 css,js,html 效果显著,视频图片不建议。
brotli_comp_level 压缩等级。
brotli_window 512k; 窗口值,压缩软件通用的概念,压缩一份数据先准备一个地方放进去然后压缩,影响速率。
brotli_min_length 最小的压缩内容长度。
其余的配置基本用不到了。
具体配置
依旧配置在 nginx.conf。

