一、概述
1.1 背景介紹
說(shuō)起Gzip壓縮,可能很多人覺(jué)得這是個(gè)老生常談的話題。但我在這幾年的運(yùn)維工作中發(fā)現(xiàn),真正把Gzip配置到位的網(wǎng)站其實(shí)不多。去年幫一個(gè)客戶做性能優(yōu)化,他們的網(wǎng)站日均帶寬消耗在2TB左右,一看Nginx配置,Gzip居然只開(kāi)了默認(rèn)的gzip on,壓縮級(jí)別是1,很多該壓的文件類型都沒(méi)加上。調(diào)整完配置后,帶寬直接降到800GB,每個(gè)月省下來(lái)的CDN費(fèi)用夠給團(tuán)隊(duì)發(fā)幾次下午茶了。
Gzip是HTTP/1.1引入的內(nèi)容編碼機(jī)制,通過(guò)DEFLATE算法對(duì)響應(yīng)體進(jìn)行壓縮。文本類內(nèi)容(HTML、CSS、JS、JSON、XML)壓縮率通常能達(dá)到60%-80%,這意味著原本100KB的文件傳輸時(shí)只需要20-40KB。在移動(dòng)網(wǎng)絡(luò)環(huán)境下,這個(gè)優(yōu)化效果特別明顯。
現(xiàn)代瀏覽器都支持Gzip解壓,服務(wù)端壓縮+客戶端解壓這個(gè)過(guò)程對(duì)用戶來(lái)說(shuō)完全透明,但帶來(lái)的體驗(yàn)提升卻是實(shí)實(shí)在在的。
1.2 技術(shù)特點(diǎn)
壓縮原理
Gzip基于LZ77算法和哈夫曼編碼,通過(guò)查找重復(fù)字符串并用更短的引用替代,再對(duì)結(jié)果進(jìn)行熵編碼。對(duì)于包含大量重復(fù)模式的文本文件效果最好,對(duì)已經(jīng)壓縮過(guò)的文件(圖片、視頻、壓縮包)幾乎沒(méi)有效果。
壓縮級(jí)別
Nginx支持1-9九個(gè)壓縮級(jí)別:
級(jí)別1:壓縮速度最快,壓縮率最低
級(jí)別9:壓縮率最高,但CPU消耗也最大
級(jí)別5-6:通常是性能和壓縮率的最佳平衡點(diǎn)
實(shí)測(cè)數(shù)據(jù)顯示,從級(jí)別5到級(jí)別9,壓縮率只提升3-5%,但CPU消耗增加40%以上。所以生產(chǎn)環(huán)境一般不建議用9。
靜態(tài)預(yù)壓縮
Nginx的gzip_static模塊支持預(yù)壓縮文件。如果存在file.js.gz,直接返回壓縮文件而不用實(shí)時(shí)壓縮,徹底消除CPU開(kāi)銷。這是高并發(fā)場(chǎng)景下的殺手級(jí)優(yōu)化。
1.3 適用場(chǎng)景
適合Gzip壓縮的內(nèi)容
HTML/CSS/JavaScript
JSON/XML/SVG
純文本文件(txt、csv、log)
字體文件(woff雖然已壓縮,但gzip還能再壓10%左右)
不適合Gzip壓縮的內(nèi)容
圖片(JPEG、PNG、WebP本身已壓縮)
視頻/音頻文件
壓縮包(zip、gz、rar)
PDF文件(內(nèi)部已壓縮)
典型應(yīng)用場(chǎng)景
API服務(wù)器:JSON響應(yīng)壓縮效果極佳
靜態(tài)資源服務(wù)器:CSS/JS壓縮節(jié)省大量帶寬
文檔站點(diǎn):HTML內(nèi)容壓縮率高
日志分析平臺(tái):大量文本數(shù)據(jù)傳輸
1.4 環(huán)境要求
| 組件 | 版本要求 | 說(shuō)明 |
|---|---|---|
| 操作系統(tǒng) | Rocky Linux 9 / Ubuntu 24.04 LTS | 內(nèi)核4.x以上 |
| Nginx | 1.26.x / 1.27.x | 需包含ngx_http_gzip_module |
| 可選模塊 | gzip_static | 靜態(tài)預(yù)壓縮支持 |
| 可選模塊 | gunzip | 為不支持gzip的客戶端解壓 |
| CPU | 多核推薦 | 實(shí)時(shí)壓縮消耗CPU |
| 內(nèi)存 | 每連接約256KB | gzip緩沖區(qū)大小 |
二、詳細(xì)步驟
2.1 準(zhǔn)備工作
確認(rèn)Nginx已編譯gzip模塊
# 查看編譯參數(shù) nginx -V 2>&1 | tr' '' '| grep gzip # 輸出應(yīng)包含: # --with-http_gzip_static_module # --with-http_gunzip_module # 如果缺少gzip_static模塊,需要重新編譯或安裝帶模塊的版本 # 官方倉(cāng)庫(kù)的nginx默認(rèn)包含這些模塊
準(zhǔn)備測(cè)試文件
# 創(chuàng)建測(cè)試目錄 mkdir -p /data/gzip-test # 生成測(cè)試文件 cat > /data/gzip-test/test.html <'EOF'Gzip壓縮測(cè)試 EOF # 創(chuàng)建一個(gè)大的JS文件用于測(cè)試 curl -o /data/gzip-test/jquery.js https://code.jquery.com/jquery-3.7.1.js 2>/dev/null ||echo'console.log("test");'> /data/gzip-test/jquery.js # 創(chuàng)建JSON測(cè)試文件 cat > /data/gzip-test/data.json <'EOF' { ? ??"users": [ ? ? ? ? {"id": 1,?"name":?"張三",?"email":?"zhangsan@example.com"}, ? ? ? ? {"id": 2,?"name":?"李四",?"email":?"lisi@example.com"}, ? ? ? ? {"id": 3,?"name":?"王五",?"email":?"wangwu@example.com"} ? ? ], ? ??"total": 3, ? ??"page": 1, ? ??"pageSize": 10 } EOF # 查看文件大小 ls -lh /data/gzip-test/Gzip壓縮效果測(cè)試頁(yè)面
這是一個(gè)用于測(cè)試Nginx Gzip壓縮效果的頁(yè)面。
重復(fù)內(nèi)容有助于提高壓縮率。
重復(fù)內(nèi)容有助于提高壓縮率。
重復(fù)內(nèi)容有助于提高壓縮率。
安裝測(cè)試工具
# Rocky Linux dnf install curl httpd-tools -y # Ubuntu apt install curl apache2-utils -y
2.2 核心配置
基礎(chǔ)Gzip配置
# /etc/nginx/nginx.conf 或 /etc/nginx/conf.d/gzip.conf
http {
# ==================== Gzip基礎(chǔ)配置 ====================
# 開(kāi)啟gzip壓縮
gzip on;
# 壓縮級(jí)別:1-9,推薦5-6
# 級(jí)別越高壓縮率越好但CPU消耗越大
gzip_comp_level 5;
# 最小壓縮文件大小
# 小于這個(gè)值的文件不壓縮(壓縮收益?。? gzip_min_length 1024;
# 壓縮緩沖區(qū)
# 32個(gè)4k的緩沖區(qū),用于存儲(chǔ)壓縮結(jié)果
gzip_buffers 32 4k;
# 壓縮HTTP版本
# 對(duì)HTTP/1.0也啟用壓縮(兼容老代理)
gzip_http_version 1.0;
# ==================== 壓縮類型配置 ====================
# 需要壓縮的MIME類型
# 注意:text/html默認(rèn)已啟用,不需要重復(fù)添加
gzip_types
# 文本類型
text/plain
text/css
text/xml
text/javascript
# 應(yīng)用類型
application/json
application/javascript
application/x-javascript
application/xml
application/xml+rss
application/xhtml+xml
application/atom+xml
application/rss+xml
# 字體類型
application/font-woff
application/font-woff2
application/vnd.ms-fontobject
application/x-font-ttf
font/opentype
font/woff
font/woff2
# 圖片類型(僅SVG,其他圖片已壓縮)
image/svg+xml
image/x-icon;
# ==================== 代理相關(guān)配置 ====================
# 針對(duì)代理請(qǐng)求的壓縮策略
# any: 對(duì)所有代理請(qǐng)求都?jí)嚎s
gzip_proxied any;
# 其他可選值:
# off: 禁止對(duì)代理請(qǐng)求壓縮
# expired: 響應(yīng)頭包含Expires且已過(guò)期
# no-cache: 響應(yīng)頭包含Cache-Control: no-cache
# no-store: 響應(yīng)頭包含Cache-Control: no-store
# private: 響應(yīng)頭包含Cache-Control: private
# no_last_modified: 響應(yīng)頭不包含Last-Modified
# no_etag: 響應(yīng)頭不包含ETag
# auth: 請(qǐng)求頭包含Authorization
# any: 所有代理請(qǐng)求
# ==================== Vary頭配置 ====================
# 在響應(yīng)頭中添加Vary: Accept-Encoding
# 告訴代理服務(wù)器根據(jù)Accept-Encoding緩存不同版本
gzip_vary on;
# ==================== 排除特定客戶端 ====================
# 禁止對(duì)特定User-Agent壓縮
# 某些老舊瀏覽器對(duì)gzip支持有問(wèn)題
gzip_disable "MSIE [1-6].";
# 也可以用正則排除更多
# gzip_disable "MSIE [1-6].|Mozilla/4";
}
靜態(tài)預(yù)壓縮配置(gzip_static)
這是我強(qiáng)烈推薦的優(yōu)化方式,特別是對(duì)于前端構(gòu)建產(chǎn)物:
http {
# 開(kāi)啟靜態(tài)預(yù)壓縮
# on: 查找.gz文件,找到就直接返回
# off: 禁用
# always: 始終返回.gz文件,不檢查客戶端是否支持
gzip_static on;
server {
listen 80;
server_name example.com;
root /data/www;
# 前端資源目錄
location /assets/ {
# 啟用靜態(tài)預(yù)壓縮
gzip_static on;
# 緩存控制
expires 1y;
add_header Cache-Control "public, immutable";
}
# API接口(實(shí)時(shí)壓縮)
location /api/ {
# API響應(yīng)需要實(shí)時(shí)壓縮
gzip on;
gzip_comp_level 5;
gzip_types application/json;
proxy_pass http://backend;
}
}
}
預(yù)壓縮文件生成腳本
#!/bin/bash
# generate_gzip.sh - 生成預(yù)壓縮文件
STATIC_DIR=${1:-/data/www/assets}
GZIP_LEVEL=${2:-9}
echo"開(kāi)始生成預(yù)壓縮文件..."
echo"目錄:$STATIC_DIR"
echo"壓縮級(jí)別:$GZIP_LEVEL"
# 需要預(yù)壓縮的文件類型
FILE_TYPES="css js html json xml svg txt"
forextin$FILE_TYPES;do
find"$STATIC_DIR"-name"*.$ext"-typef |whilereadfile;do
# 跳過(guò)已經(jīng)是.gz的文件
[["$file"== *.gz ]] &&continue
gz_file="${file}.gz"
# 如果.gz文件不存在或源文件更新,重新壓縮
if[[ ! -f"$gz_file"]] || [["$file"-nt"$gz_file"]];then
echo"壓縮:$file"
gzip -${GZIP_LEVEL}-c"$file">"$gz_file"
# 保持時(shí)間戳一致
touch -r"$file""$gz_file"
fi
done
done
echo"預(yù)壓縮完成!"
# 統(tǒng)計(jì)壓縮效果
echo""
echo"=== 壓縮效果統(tǒng)計(jì) ==="
find"$STATIC_DIR"-name"*.gz"-typef |whilereadgz_file;do
orig_file="${gz_file%.gz}"
if[[ -f"$orig_file"]];then
orig_size=$(stat-c%s"$orig_file"2>/dev/null ||stat-f%z"$orig_file")
gz_size=$(stat-c%s"$gz_file"2>/dev/null ||stat-f%z"$gz_file")
ratio=$(echo"scale=2; (1 -$gz_size/$orig_size) * 100"| bc)
echo"$orig_file:$orig_size->$gz_size(節(jié)省${ratio}%)"
fi
done
2.3 啟動(dòng)和驗(yàn)證
配置檢查
# 檢查配置語(yǔ)法 nginx -t # 查看gzip相關(guān)配置 nginx -T | grep -i gzip # 重載配置 nginx -s reload
基礎(chǔ)驗(yàn)證
# 測(cè)試gzip是否生效 # 注意:必須發(fā)送Accept-Encoding頭 # 不帶壓縮請(qǐng)求 curl -I http://localhost/test.html # Content-Length: 1234 (原始大?。? # 帶壓縮請(qǐng)求 curl -I -H"Accept-Encoding: gzip"http://localhost/test.html # Content-Encoding: gzip # Content-Length: 456 (壓縮后大?。?# Vary: Accept-Encoding # 獲取完整響應(yīng)并解壓 curl -H"Accept-Encoding: gzip"http://localhost/test.html | gunzip
詳細(xì)測(cè)試腳本
#!/bin/bash
# test_gzip.sh - 測(cè)試Gzip壓縮效果
URL=${1//localhost}
FILES=("test.html""jquery.js""data.json""style.css")
echo"=== Gzip壓縮效果測(cè)試 ==="
echo"目標(biāo):$URL"
echo""
printf"%-30s %10s %10s %10s
""文件""原始大小""壓縮大小""壓縮率"
printf"%-30s %10s %10s %10s
""----""--------""--------""------"
forfilein"${FILES[@]}";do
# 獲取未壓縮大小
orig_size=$(curl -sI"$URL/$file"2>/dev/null | grep -i content-length | awk'{print $2}'| tr -d'
')
# 獲取壓縮后大小
gzip_size=$(curl -sI -H"Accept-Encoding: gzip""$URL/$file"2>/dev/null | grep -i content-length | awk'{print $2}'| tr -d'
')
# 檢查是否啟用了壓縮
encoding=$(curl -sI -H"Accept-Encoding: gzip""$URL/$file"2>/dev/null | grep -i content-encoding)
if[[ -n"$encoding"]] && [[ -n"$orig_size"]] && [[ -n"$gzip_size"]];then
ratio=$(echo"scale=1; (1 -$gzip_size/$orig_size) * 100"| bc)
printf"%-30s %10s %10s %9s%%
""$file""$orig_size""$gzip_size""$ratio"
else
printf"%-30s %10s %10s %10s
""$file""$orig_size""${gzip_size:-N/A}""未壓縮"
fi
done
壓力測(cè)試對(duì)比
# 無(wú)壓縮測(cè)試 ab -n 10000 -c 100 http://localhost/jquery.js # 記錄:Requests per second, Transfer rate # 有壓縮測(cè)試 ab -n 10000 -c 100 -H"Accept-Encoding: gzip"http://localhost/jquery.js # 記錄:Requests per second, Transfer rate # 對(duì)比傳輸量和吞吐量的變化
三、示例代碼和配置
3.1 完整配置示例
生產(chǎn)環(huán)境完整配置
# /etc/nginx/conf.d/gzip-production.conf
# 生產(chǎn)環(huán)境Gzip完整配置
http {
# ==================== Gzip全局配置 ====================
# 基礎(chǔ)開(kāi)關(guān)
gzip on;
# 壓縮級(jí)別:生產(chǎn)環(huán)境推薦5
gzip_comp_level 5;
# 最小壓縮大?。盒∮?KB的文件不壓縮
gzip_min_length 1024;
# 壓縮緩沖區(qū)配置
# 16個(gè)8k的緩沖區(qū),適合中等大小文件
gzip_buffers 16 8k;
# HTTP版本
gzip_http_version 1.1;
# 啟用Vary頭
gzip_vary on;
# 對(duì)代理請(qǐng)求的處理
gzip_proxied any;
# 禁用對(duì)老舊IE的壓縮
gzip_disable "MSIE [1-6].(?!.*SV1)";
# 壓縮類型(完整列表)
gzip_types
# 文本
text/plain
text/css
text/xml
text/javascript
text/x-component
text/cache-manifest
# 應(yīng)用
application/json
application/javascript
application/x-javascript
application/xml
application/xml+rss
application/xhtml+xml
application/atom+xml
application/rss+xml
application/ld+json
application/manifest+json
application/schema+json
application/geo+json
application/vnd.api+json
application/vnd.ms-fontobject
application/x-font-ttf
application/x-font-opentype
application/x-font-truetype
application/x-web-app-manifest+json
# 字體
font/eot
font/opentype
font/otf
font/woff
font/woff2
# 圖片(僅矢量)
image/svg+xml
image/x-icon
image/bmp
image/vnd.microsoft.icon;
# ==================== 靜態(tài)預(yù)壓縮 ====================
# 全局開(kāi)啟靜態(tài)預(yù)壓縮
gzip_static on;
}
分場(chǎng)景配置示例
server {
listen 80;
server_name example.com;
root /data/www;
# ==================== 場(chǎng)景一:靜態(tài)資源CDN源站 ====================
location /static/ {
# 使用預(yù)壓縮文件(最高壓縮級(jí)別)
gzip_static on;
# 如果沒(méi)有預(yù)壓縮文件,實(shí)時(shí)壓縮
gzip on;
gzip_comp_level 6;
# 長(zhǎng)緩存
expires 1y;
add_header Cache-Control "public, immutable";
}
# ==================== 場(chǎng)景二:API響應(yīng)壓縮 ====================
location /api/ {
# API響應(yīng)通常是JSON,必須實(shí)時(shí)壓縮
gzip on;
gzip_comp_level 5;
gzip_min_length 256; # API響應(yīng)可能較小,降低閾值
gzip_types application/json;
# 禁用代理緩存(API響應(yīng)經(jīng)常變化)
add_header Cache-Control "no-store";
proxy_pass http://api_backend;
proxy_set_header Accept-Encoding ""; # 不讓后端壓縮,Nginx統(tǒng)一處理
}
# ==================== 場(chǎng)景三:HTML頁(yè)面 ====================
location / {
gzip on;
gzip_comp_level 5;
gzip_types text/html;
# HTML不緩存,保證獲取最新內(nèi)容
expires -1;
add_header Cache-Control "no-cache, must-revalidate";
try_files $uri $uri/ /index.html;
}
# ==================== 場(chǎng)景四:大文件下載 ====================
location /downloads/ {
# 大文件不壓縮,避免占用大量?jī)?nèi)存和CPU
gzip off;
# 開(kāi)啟sendfile高效傳輸
sendfile on;
tcp_nopush on;
# 限速防止帶寬耗盡
limit_rate 1m;
}
# ==================== 場(chǎng)景五:WebSocket ====================
location /ws/ {
# WebSocket不能使用gzip
gzip off;
proxy_pass http://websocket_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
3.2 實(shí)際應(yīng)用案例
案例一:電商網(wǎng)站首頁(yè)優(yōu)化
我們有個(gè)電商客戶,首頁(yè)HTML有800KB(包含大量商品數(shù)據(jù)),加載時(shí)間超過(guò)3秒。
優(yōu)化前的情況:
首頁(yè)大小: 812KB 加載時(shí)間: 3.2s(3G網(wǎng)絡(luò)) Gzip: 未啟用
優(yōu)化方案:
location / {
gzip on;
gzip_comp_level 6; # 首頁(yè)訪問(wèn)頻繁,適當(dāng)提高壓縮級(jí)別
gzip_types text/html application/json;
gzip_min_length 256;
# 啟用ETag便于緩存驗(yàn)證
etag on;
try_files $uri @backend;
}
location @backend {
proxy_pass http://backend;
# 后端響應(yīng)也要壓縮
gzip on;
gzip_proxied any;
}
優(yōu)化后:
首頁(yè)大小: 812KB -> 156KB(壓縮率81%) 加載時(shí)間: 3.2s -> 0.8s 帶寬節(jié)省: 約80%
案例二:API服務(wù)壓縮優(yōu)化
某金融APP后端API,每天數(shù)千萬(wàn)次調(diào)用,返回JSON數(shù)據(jù)。
問(wèn)題分析:
平均響應(yīng)大小: 15KB 日請(qǐng)求量: 5000萬(wàn)次 日帶寬消耗: 約700TB 帶寬成本: 高
配置方案:
upstream api_servers {
server 10.0.1.10:8080;
server 10.0.1.11:8080;
keepalive 100;
}
server {
listen 80;
server_name api.example.com;
location / {
# JSON響應(yīng)壓縮
gzip on;
gzip_comp_level 5;
gzip_min_length 512;
gzip_types application/json;
gzip_proxied any;
gzip_vary on;
proxy_pass http://api_servers;
proxy_http_version 1.1;
proxy_set_header Connection "";
# 重要:告訴后端不要壓縮,統(tǒng)一由Nginx處理
proxy_set_header Accept-Encoding "identity";
# 緩沖設(shè)置,避免邊收邊發(fā)
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 8 32k;
}
}
優(yōu)化效果:
平均響應(yīng)大小: 15KB -> 3KB(壓縮率80%) 日帶寬消耗: 700TB -> 140TB 月度帶寬成本節(jié)省: 約560TB * 單價(jià) CPU增加: 約15%(可接受)
案例三:前端構(gòu)建產(chǎn)物預(yù)壓縮
現(xiàn)代前端項(xiàng)目使用Webpack/Vite構(gòu)建,結(jié)合CI/CD自動(dòng)生成預(yù)壓縮文件。
Vite配置:
// vite.config.js
import{ defineConfig }from'vite'
importviteCompressionfrom'vite-plugin-compression'
exportdefaultdefineConfig({
plugins: [
viteCompression({
algorithm:'gzip',
ext:'.gz',
threshold:1024, // 大于1KB才壓縮
deleteOriginFile:false// 保留原文件
}),
// 同時(shí)生成Brotli壓縮
viteCompression({
algorithm:'brotliCompress',
ext:'.br',
threshold:1024
})
]
})
Nginx配置:
location /assets/ {
# 優(yōu)先返回Brotli壓縮(壓縮率更高)
brotli_static on;
# 其次返回Gzip
gzip_static on;
# 如果都沒(méi)有,實(shí)時(shí)壓縮
gzip on;
gzip_comp_level 5;
expires max;
add_header Cache-Control "public, immutable";
}
CI/CD pipeline腳本:
#!/bin/bash
# build.sh - 前端構(gòu)建腳本
# 構(gòu)建
npm run build
# 生成預(yù)壓縮文件
cddist
# Gzip壓縮
find . -typef ( -name"*.js"-o -name"*.css"-o -name"*.html"-o -name"*.json")
-execgzip -9 -k {} ;
# Brotli壓縮(如果安裝了brotli)
ifcommand-v brotli &> /dev/null;then
find . -typef ( -name"*.js"-o -name"*.css"-o -name"*.html"-o -name"*.json")
-execbrotli -9 -k {} ;
fi
# 統(tǒng)計(jì)
echo"=== 壓縮統(tǒng)計(jì) ==="
du -sh dist/
find dist -name"*.gz"| wc -l
find dist -name"*.br"| wc -l
案例四:不同壓縮級(jí)別性能對(duì)比測(cè)試
我在一臺(tái)4核8G的服務(wù)器上做了詳細(xì)測(cè)試,文件是280KB的jquery.min.js:
| 壓縮級(jí)別 | 壓縮后大小 | 壓縮率 | 壓縮耗時(shí) | QPS |
|---|---|---|---|---|
| 1 | 98KB | 65% | 0.8ms | 12000 |
| 2 | 94KB | 66% | 0.9ms | 11500 |
| 3 | 91KB | 67% | 1.1ms | 10800 |
| 4 | 88KB | 69% | 1.4ms | 9500 |
| 5 | 85KB | 70% | 1.8ms | 8200 |
| 6 | 84KB | 70% | 2.5ms | 6800 |
| 7 | 83KB | 70% | 3.8ms | 5200 |
| 8 | 82KB | 71% | 6.2ms | 3500 |
| 9 | 82KB | 71% | 12ms | 1800 |
| 預(yù)壓縮 | 82KB | 71% | 0ms | 35000 |
結(jié)論:
級(jí)別5是性價(jià)比最高的選擇
級(jí)別6-9收益遞減明顯,不推薦
預(yù)壓縮性能碾壓實(shí)時(shí)壓縮,強(qiáng)烈推薦
四、最佳實(shí)踐和注意事項(xiàng)
4.1 最佳實(shí)踐
1. 根據(jù)內(nèi)容類型選擇壓縮策略
# 高頻訪問(wèn)的靜態(tài)資源:預(yù)壓縮
location ~* .(js|css)$ {
gzip_static on;
gzip on;
gzip_comp_level 5;
}
# 動(dòng)態(tài)生成的內(nèi)容:實(shí)時(shí)壓縮
location /api/ {
gzip on;
gzip_comp_level 5;
}
# 已壓縮的媒體文件:不壓縮
location ~* .(jpg|jpeg|png|gif|mp4|webm|zip|gz)$ {
gzip off;
}
2. 合理設(shè)置gzip_min_length
# 太小的文件壓縮后可能反而變大(gzip頭部開(kāi)銷) # 推薦設(shè)置: gzip_min_length 1024; # 通用場(chǎng)景 # API場(chǎng)景可以降低閾值(JSON通常較小但壓縮率高) gzip_min_length 256;
3. gzip_vary必須開(kāi)啟
# 必須開(kāi)啟,否則CDN/代理可能返回錯(cuò)誤的緩存 gzip_vary on; # 這會(huì)在響應(yīng)頭添加: # Vary: Accept-Encoding # 告訴緩存服務(wù)器:同一URL根據(jù)Accept-Encoding返回不同內(nèi)容
4. 統(tǒng)一在Nginx層壓縮
# 不要讓后端應(yīng)用也壓縮,會(huì)造成:
# 1. 重復(fù)壓縮浪費(fèi)CPU
# 2. 壓縮策略不統(tǒng)一
# 3. 調(diào)試?yán)щy
location /api/ {
proxy_pass http://backend;
# 告訴后端不要壓縮
proxy_set_header Accept-Encoding "identity";
# 由Nginx統(tǒng)一壓縮
gzip on;
gzip_proxied any;
}
5. 監(jiān)控壓縮效果
# 自定義日志格式記錄壓縮信息
log_format compression '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$gzip_ratio';
# $gzip_ratio 顯示壓縮比例,如 "2.50"表示壓縮到原來(lái)的1/2.5
4.2 注意事項(xiàng)
常見(jiàn)錯(cuò)誤表
| 錯(cuò)誤 | 原因 | 解決方案 |
|---|---|---|
| gzip不生效 | 請(qǐng)求頭缺少Accept-Encoding | 檢查客戶端/代理是否移除了該頭 |
| 壓縮率低 | 文件已壓縮或內(nèi)容隨機(jī)性高 | 檢查文件類型,已壓縮文件不要重復(fù)壓縮 |
| CPU飆高 | 壓縮級(jí)別過(guò)高或并發(fā)過(guò)大 | 降低壓縮級(jí)別或使用預(yù)壓縮 |
| 響應(yīng)變慢 | gzip_buffers配置不當(dāng) | 增大緩沖區(qū)或降低壓縮級(jí)別 |
| CDN緩存異常 | 未設(shè)置Vary頭 | 開(kāi)啟gzip_vary on |
| 部分請(qǐng)求未壓縮 | 小于gzip_min_length | 降低閾值或接受不壓縮 |
| 亂碼 | 客戶端不支持gzip | 使用gzip_disable排除 |
性能陷阱
# 陷阱1:對(duì)所有內(nèi)容都?jí)嚎s # 錯(cuò)誤 gzip_types *; # 正確:只壓縮文本類型 # 陷阱2:壓縮級(jí)別設(shè)置過(guò)高 # 錯(cuò)誤 gzip_comp_level 9; # CPU殺手 # 正確 gzip_comp_level 5; # 性價(jià)比最高 # 陷阱3:不限制最小壓縮大小 # 錯(cuò)誤 gzip_min_length 0; # 所有文件都?jí)嚎s # 正確 gzip_min_length 1024; # 小文件不壓縮 # 陷阱4:對(duì)圖片視頻壓縮 # 錯(cuò)誤 gzip_types image/jpeg image/png video/mp4; # 這些格式已經(jīng)壓縮過(guò),再壓縮只浪費(fèi)CPU # 陷阱5:沒(méi)有預(yù)壓縮高頻文件 # 錯(cuò)誤:每次請(qǐng)求都實(shí)時(shí)壓縮 # 正確:構(gòu)建時(shí)預(yù)壓縮 + gzip_static on
安全考慮
# BREACH攻擊防護(hù)
# 對(duì)包含敏感信息的HTTPS響應(yīng),攻擊者可能通過(guò)壓縮率變化推測(cè)內(nèi)容
# 防護(hù)方案:
# 1. 對(duì)包含敏感數(shù)據(jù)的響應(yīng)禁用壓縮
location /api/sensitive/ {
gzip off;
}
# 2. 在響應(yīng)中添加隨機(jī)填充
# 需要后端配合實(shí)現(xiàn)
# 3. 使用SameSite Cookie
add_header Set-Cookie "session=xxx; SameSite=Strict";
五、故障排查和監(jiān)控
5.1 故障排查
問(wèn)題一:Gzip完全不生效
# 排查步驟 # 1. 檢查模塊是否加載 nginx -V 2>&1 | grep -o'http_gzip_module' # 2. 檢查配置是否生效 nginx -T | grep gzip # 3. 測(cè)試請(qǐng)求 curl -I -H"Accept-Encoding: gzip"http://localhost/test.html # 4. 如果響應(yīng)頭沒(méi)有Content-Encoding: gzip,檢查: # - gzip是否為on # - 文件類型是否在gzip_types中 # - 文件大小是否大于gzip_min_length # - 是否被gzip_disable規(guī)則排除 # 5. 查看錯(cuò)誤日志 tail -f /var/log/nginx/error.log
問(wèn)題二:部分文件未壓縮
# 常見(jiàn)原因:MIME類型不在gzip_types中 # 檢查文件MIME類型 file --mime-type test.json # application/json # 檢查Nginx的MIME配置 cat /etc/nginx/mime.types | grep json # 確保gzip_types包含該類型 nginx -T | grep gzip_types
問(wèn)題三:壓縮后文件變大
# 小文件或高熵內(nèi)容壓縮后可能變大 # 檢查原始文件大小 ls -la test.html # 如果小于1KB,提高gzip_min_length # 或者檢查文件內(nèi)容是否已壓縮/隨機(jī)數(shù)據(jù)
問(wèn)題四:CPU占用過(guò)高
# 檢查壓縮級(jí)別 nginx -T | grep gzip_comp_level # 查看Nginx進(jìn)程CPU top -p $(pgrep -d','nginx) # 解決方案: # 1. 降低壓縮級(jí)別 # 2. 使用預(yù)壓縮 # 3. 增加gzip_min_length # 4. 限制壓縮類型
調(diào)試腳本
#!/bin/bash # debug_gzip.sh - Gzip配置調(diào)試 URL=$1 if[ -z"$URL"];then echo"用法:$0" exit1 fi echo"=== Gzip調(diào)試:$URL===" echo"" echo"--- 請(qǐng)求頭 ---" curl -sI"$URL"| head -20 echo"" echo"--- 帶Accept-Encoding的請(qǐng)求 ---" curl -sI -H"Accept-Encoding: gzip, deflate""$URL"| head -20 echo"" echo"--- 關(guān)鍵響應(yīng)頭 ---" echo"Content-Encoding:$(curl -sI -H 'Accept-Encoding: gzip' "$URL" | grep -i content-encoding)" echo"Content-Length (原始):$(curl -sI "$URL" | grep -i content-length)" echo"Content-Length (壓縮):$(curl -sI -H 'Accept-Encoding: gzip' "$URL" | grep -i content-length)" echo"Vary:$(curl -sI -H 'Accept-Encoding: gzip' "$URL" | grep -i vary)" echo"" echo"--- 內(nèi)容類型 ---" echo"Content-Type:$(curl -sI "$URL" | grep -i content-type)"
5.2 性能監(jiān)控
Nginx狀態(tài)監(jiān)控
# 啟用狀態(tài)頁(yè)
location /nginx_status {
stub_status on;
allow 127.0.0.1;
deny all;
}
壓縮率日志
# 記錄壓縮比例
log_format gzip_log '$remote_addr [$time_local] "$request" '
'$status $body_bytes_sent '
'gzip_ratio=$gzip_ratio '
'rt=$request_time';
access_log /var/log/nginx/gzip.log gzip_log;
分析腳本
#!/bin/bash
# analyze_gzip.sh - 分析Gzip壓縮效果
LOG_FILE=${1:-/var/log/nginx/gzip.log}
echo"=== Gzip壓縮效果分析 ==="
echo""
echo"--- 壓縮比例分布 ---"
awk'{
for(i=1;i<=NF;i++) {
? ? ? ? if($i ~ /gzip_ratio=/) {
? ? ? ? ? ? split($i, a, "=")
? ? ? ? ? ? ratio = a[2]
? ? ? ? ? ? if (ratio == "-") {
? ? ? ? ? ? ? ? none++
? ? ? ? ? ? } else if (ratio < 1.5) {
? ? ? ? ? ? ? ? low++
? ? ? ? ? ? } else if (ratio < 3) {
? ? ? ? ? ? ? ? medium++
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? high++
? ? ? ? ? ? }
? ? ? ? }
? ? }
}
END {
? ? total = none + low + medium + high
? ? printf "未壓縮: %d (%.1f%%)
", none, none/total*100
? ? printf "低壓縮(<1.5x): %d (%.1f%%)
", low, low/total*100
? ? printf "中壓縮(1.5-3x): %d (%.1f%%)
", medium, medium/total*100
? ? printf "高壓縮(>3x): %d (%.1f%%)
", high, high/total*100
}'$LOG_FILE
echo""
echo"--- 按文件類型統(tǒng)計(jì) ---"
awk'{
# 提取URL和壓縮比
url = $5
gsub(/"/, "", url)
for(i=1;i<=NF;i++) {
? ? ? ? if($i ~ /gzip_ratio=/) {
? ? ? ? ? ? split($i, a, "=")
? ? ? ? ? ? ratio = a[2]
? ? ? ? }
? ? }
? ? # 提取擴(kuò)展名
? ? n = split(url, parts, ".")
? ? ext = parts[n]
? ? n = split(ext, parts, "?")
? ? ext = parts[1]
? ? if (ratio != "-" && ratio > 0) {
count[ext]++
sum[ext] += ratio
}
}
END {
printf "%-10s %10s %15s
", "類型", "請(qǐng)求數(shù)", "平均壓縮比"
for (ext in count) {
printf "%-10s %10d %15.2f
", ext, count[ext], sum[ext]/count[ext]
}
}'$LOG_FILE| sort -t$' '-k2 -rn
Prometheus監(jiān)控指標(biāo)
# prometheus.yml 抓取配置 scrape_configs: -job_name:'nginx' static_configs: -targets:['localhost:9113'] # 自定義指標(biāo)(需要nginx-prometheus-exporter) # nginx_http_requests_total # nginx_connections_active # nginx_connections_reading # nginx_connections_writing
5.3 備份與恢復(fù)
配置備份
#!/bin/bash # backup_gzip_config.sh BACKUP_DIR="/backup/nginx/gzip" DATE=$(date +%Y%m%d) mkdir -p$BACKUP_DIR # 備份gzip相關(guān)配置 nginx -T | grep -A 100'gzip'>$BACKUP_DIR/gzip_config_$DATE.txt # 備份完整配置 cp -r /etc/nginx/conf.d/$BACKUP_DIR/conf.d_$DATE/ # 保留30天 find$BACKUP_DIR-mtime +30 -delete echo"備份完成:$BACKUP_DIR"
快速回滾
#!/bin/bash # rollback_gzip.sh - 回滾到默認(rèn)gzip配置 cat > /etc/nginx/conf.d/gzip.conf <'EOF' # Gzip默認(rèn)配置 gzip on; gzip_comp_level 5; gzip_min_length 1024; gzip_types text/plain text/css application/json application/javascript text/xml; gzip_vary on; EOF nginx -t && nginx -s reload echo?"已回滾到默認(rèn)gzip配置"
六、總結(jié)
6.1 技術(shù)要點(diǎn)回顧
Gzip壓縮優(yōu)化的核心就是這幾點(diǎn):
選對(duì)壓縮級(jí)別:生產(chǎn)環(huán)境用5-6,別用9
選對(duì)壓縮類型:只壓縮文本類,別碰圖片視頻
用好預(yù)壓縮:高頻訪問(wèn)的靜態(tài)資源必須預(yù)壓縮
開(kāi)啟Vary頭:gzip_vary on必須有
統(tǒng)一入口壓縮:在Nginx層統(tǒng)一處理,后端不壓縮
關(guān)鍵配置速記:
gzip on; gzip_comp_level 5; gzip_min_length 1024; gzip_types text/plain text/css application/json application/javascript; gzip_vary on; gzip_static on;
6.2 進(jìn)階學(xué)習(xí)方向
Brotli壓縮:比Gzip壓縮率高15-20%,現(xiàn)代瀏覽器都支持
Zstd壓縮:Facebook開(kāi)源的新一代壓縮算法
動(dòng)態(tài)壓縮級(jí)別:根據(jù)CPU負(fù)載動(dòng)態(tài)調(diào)整壓縮級(jí)別
邊緣壓縮:在CDN邊緣節(jié)點(diǎn)進(jìn)行壓縮
6.3 參考資料
Nginx Gzip模塊文檔:https://nginx.org/en/docs/http/ngx_http_gzip_module.html
Gzip vs Brotli對(duì)比:https://www.keycdn.com/blog/brotli-compression
HTTP壓縮機(jī)制RFC:https://tools.ietf.org/html/rfc7231#section-3.1.2.2
BREACH攻擊說(shuō)明:https://breachattack.com/
附錄
A. 命令速查表
| 命令 | 說(shuō)明 |
|---|---|
| gzip -9 file.js | 壓縮文件(最高級(jí)別) |
| gzip -k file.js | 壓縮并保留原文件 |
| gzip -l file.js.gz | 查看壓縮信息 |
| gunzip file.js.gz | 解壓文件 |
| zcat file.js.gz | 查看壓縮文件內(nèi)容 |
| curl -I -H "Accept-Encoding: gzip" URL | 測(cè)試gzip是否生效 |
B. 配置參數(shù)詳解
| 參數(shù) | 默認(rèn)值 | 說(shuō)明 |
|---|---|---|
| gzip | off | 開(kāi)啟/關(guān)閉gzip |
| gzip_comp_level | 1 | 壓縮級(jí)別1-9 |
| gzip_min_length | 20 | 最小壓縮大?。ㄗ止?jié)) |
| gzip_buffers | 32 4k | 壓縮緩沖區(qū)配置 |
| gzip_types | text/html | 壓縮的MIME類型 |
| gzip_vary | off | 是否添加Vary頭 |
| gzip_proxied | off | 代理請(qǐng)求壓縮策略 |
| gzip_disable | - | 禁用壓縮的User-Agent |
| gzip_http_version | 1.1 | 啟用壓縮的最低HTTP版本 |
| gzip_static | off | 靜態(tài)預(yù)壓縮開(kāi)關(guān) |
C. 術(shù)語(yǔ)表
| 術(shù)語(yǔ) | 解釋 |
|---|---|
| Gzip | GNU zip,一種基于DEFLATE算法的壓縮格式 |
| DEFLATE | 結(jié)合LZ77和霍夫曼編碼的壓縮算法 |
| Content-Encoding | HTTP響應(yīng)頭,指示內(nèi)容的編碼方式 |
| Accept-Encoding | HTTP請(qǐng)求頭,告知服務(wù)器客戶端支持的編碼 |
| Vary | HTTP響應(yīng)頭,指示緩存應(yīng)根據(jù)哪些請(qǐng)求頭區(qū)分響應(yīng) |
| Transfer-Encoding | 傳輸編碼,chunked表示分塊傳輸 |
| MIME Type | 多用途互聯(lián)網(wǎng)郵件擴(kuò)展類型,標(biāo)識(shí)內(nèi)容格式 |
| Brotli | Google開(kāi)發(fā)的新一代壓縮算法,壓縮率優(yōu)于Gzip |
-
算法
+關(guān)注
關(guān)注
23文章
4780瀏覽量
97941 -
字符串
+關(guān)注
關(guān)注
1文章
596瀏覽量
23153 -
nginx
+關(guān)注
關(guān)注
0文章
184瀏覽量
13081
原文標(biāo)題:Nginx Gzip壓縮配置指南:流量節(jié)省60%的秘密
文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
如何使用GZip的比特流完成重新配置?
nginx錯(cuò)誤頁(yè)面配置
主要學(xué)習(xí)下nginx的安裝配置
運(yùn)行nginx所需的最低配置
python解壓tar/gzip/zip格式壓縮包
Spring Boot+Filter實(shí)現(xiàn)Gzip壓縮超大json對(duì)象
Nginx常用的配置和基本功能講解
深入淺出了解華為云 API 網(wǎng)關(guān)的 Gzip 功能
如何使用gzip壓縮和解壓縮技術(shù)
nginx負(fù)載均衡配置介紹
深度解析Nginx Gzip指令:優(yōu)化網(wǎng)站性能與加速加載速度的關(guān)鍵工具
Nginx配置終極指南
Nginx Gzip壓縮配置指南
評(píng)論