nginx系列之gzip模块的用法和测评

时间:2022-06-18 19:58:27

1、前言

gzip在*nix系统中是个压缩命令,用于把文件压缩成.gz后缀的文件,以减小磁盘占用空间。与之相对应的是命令gunzip,用于解压缩用gzip方法压缩的文件。nginx每天会对当天的访问日志进行压缩,通常在其日志文件目录下也可看到一大堆的access.log-yyyymmdd.gz文件。

nginx有个gzip模块,用于对输出到客户端的内容进行压缩,以减小传输文件体积,减少对网络带宽的占用。在Web应用中通常启用gzip压缩,用来缩短响应时间,提升用户体验。当然,服务器端要压缩,客户端必须解压缩,这都将占用cpu时间。不过,由于传输内容减小了,传输过程中,各网卡、路由器、交换机对数据包的处理时间也会缩短。gzip压缩是就在这里赢得了时间。

2、指令说明

gzip压缩功能要启用,必须满足以下几个条件:

  • 客户端发送的HTTP报头必须含有 “Accept-Encoding” 字段,且其值包含 “gzip” 这个压缩类型。一般浏览器都会发 “Accept-Encoding:gzip, deflate, sdch” 这样的报头。

  • 服务器做响应的配置,以nginx为例,示例配置如下:

# 对static目录下js、css、jpg、jpeg、png、gif后缀的文件启用gzip压缩功能
location ~ /static/(.+)\.(js|css|jpg|jpeg|png|gif) {
gzip on; # 启用gzip压缩,默认是off,不启用
# 对js、css、jpg、png、gif格式的文件启用gzip压缩功能
gzip_types application/javascript text/css image/jpeg image/png image/gif;
gzip_min_length 1024; # 所压缩文件的最小值,小于这个的不会压缩
gzip_buffers 4 1k; # 设置压缩响应的缓冲块的大小和个数,默认是内存一个页的大小
gzip_comp_level 1; # 压缩水平,默认1。取值范围1-9,取值越大压缩比率越大,但越耗cpu时间
}

如果服务器启用了gzip压缩,那么响应头会包含 Content-Encoding:gzip, 客户端根据这个来判断服务器返回的内容是否真正为gzip压缩过的内容。

3、对各文件的压缩比率测试

为方便对文件批量测试,写了个php小程序。

该程序处理的服务器返回的传输类型为分块传输,即带 “Transfer-Encoding:chunked” HTTP响应头。

function testGzip($host, $uri) {
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_connect($socket, '127.0.0.1', 80);

$request = "GET $uri HTTP/1.1\r\n";
$request .= "Host: $host\r\n";
$request .= "Accept-Encoding: gzip\r\n";
$request .= "Connection: Keep-Alive\r\n\r\n";

socket_write($socket, $request, strlen($request));

$headers = [];
while (($line = socket_read($socket, 1024, PHP_NORMAL_READ))) {
socket_read($socket, 1, PHP_BINARY_READ);
if ($line == "\r") {
break;
}
$headers[] = rtrim($line, "\r");
}

$totalSize = 0;
$chunkSizeList = [];
$data = "";

while (true) {
$lenx = rtrim(socket_read($socket, 1024, PHP_NORMAL_READ), "\r");

socket_read($socket, 1, PHP_BINARY_READ);
$len = hexdec($lenx);

if ($len == 0) {
socket_read($socket, 2, PHP_BINARY_READ);
break;
} else {
//echo 'len=', $len, PHP_EOL;
}

$chunkSizeList[] = $len;
$totalSize += $len;

$data .= socket_read($socket, $len, PHP_BINARY_READ);
socket_read($socket, 2, PHP_BINARY_READ);
//usleep(10000);
}

socket_close($socket);

$decodedData = gzdecode($data);
#echo $decodedData;
return [$headers, $chunkSizeList, $totalSize, strlen($decodedData)];
}

function batchGzipTest($host, $basePath, $files) {
$stats = [];

foreach ($files as $jsFile) {
$stats[$jsFile] = testGzip($host, $basePath . $jsFile);
}

echo "|文件名|初始大小|压缩后大小|压缩比率|", PHP_EOL;
echo "|------|:-----|:-----|:-----|", PHP_EOL;
foreach($stats as $jsFile => $v) {
echo "|", $jsFile, "|", $v[3], "|", $v[2], "|", sprintf("%.2f", ($v[3]-$v[2])/$v[3]*100), "%", "|", PHP_EOL;
}
}

使用示例:

$host = 'invo.com';

$jsPath = '/static/js/';

$jsFiles = [
'arttemplate.js',
'bootstrap.min.js',
'fastclick.min.js',
'jquery220.min.js',
'moment.min.js',
'vue.js',
];

batchGzipTest($host, $jsPath, $jsFiles);

3.1 js文件压缩比率测试

对常用的6个js文件做了测试,结果如下:

文件名 初始大小 压缩后大小 压缩比率
arttemplate.js 4449 2257 49.27%
bootstrap.min.js 36868 11804 67.98%
fastclick.min.js 8776 3124 64.40%
jquery220.min.js 85589 34942 59.17%
moment.min.js 40737 15838 61.12%
vue.js 222777 75157 66.26%

最小49.27%,最大67.98%,还算不错!!

3.2 css文件压缩比率测试

对5个css文件进行测试:

文件名 初始大小 压缩后大小 压缩比率
bootstrap.min.css 121260 25198 79.22%
citheme.css 2486 1186 52.29%
datepicker3.css 33745 3867 88.54%
mui.min.css 77557 16183 79.13%
slider.css 8486 1745 79.44%

最小52.29%,最大88.64%,相当可以!!

3.3 图片文件压缩比率测试

3个png文件,2个jpg文件。

文件名 初始大小 压缩后大小 压缩比率
1.png 16953 16882 0.42%
2.png 117010 116875 0.12%
3.png 66492 62771 5.60%
4.jpg 775702 771901 0.49%
5.jpg 620888 618391 0.40%

没什么效果,令人失望!!估计是因为png、jpeg这些格式的图片已经是压缩过了的缘故。

3.4 html文件压缩比率测试

随机对5个html文件进行测试。

文件名 初始大小 压缩后大小 压缩比率
genindex.html 116025 17769 84.69%
index.html 53112 8726 83.57%
search.html 33589 6495 80.66%
license.html 35035 7285 79.21%
DCO.html 35168 7258 79.36%

效果比css文件的还要好!!

总结:gzip压缩对文本文件压缩效果非常好(40%~80%),而对图片文件效果甚微。实际应用中可以考虑对js、html、css格式的文件开启gzip压缩。估计json也是不错的,读者有兴趣可以自己去测试下。

4、后记

这篇文章快写完时,MarkDown竟然出问题了,说要重新加载,结果内容全没了。多么痛的领悟!只得收拾残碎的记忆又重新写了一遍。