首頁 > 軟體

Nginx 請求壓縮的實現(動態壓縮,靜態壓縮)

2023-03-05 14:04:54

一、介紹

請求壓縮,是將伺服器的結果通過 Nginx 將內容進行壓縮後,在傳送給使用者端,降低網路傳輸壓力,提升傳輸效率。

常見的兩種請求方式是: gzip 、brotli(Google),相當於 brotli 的效率會高,後續內容詳解。

請求壓縮的話分為:動態壓縮,靜態壓縮,動態壓縮會導致 Nginx內部的 sendfile 失效。對於一些不變的內容可以使用靜態壓縮,提升請求效率 。

用於請求結果的壓縮,需要使用者端和伺服器雙方支援壓縮協定,在伺服器進行結果的壓縮,使用者端進行資料解壓縮,在壓縮會佔用伺服器端一些效能效率,這個損耗根據壓縮的等級來定,等級越高,耗損越大。可以減少網路傳輸壓力。

壓縮只針對於 代理方式請求才生效。

二、請求壓縮的流程

執行的流程是:使用者端向伺服器端傳送請求,nginx 接收請求之後,會向上遊伺服器伺服器傳送請求,Nginx和上游伺服器之間會建立網路通道,之間會進行資料的傳輸,在這裡如果是開啟了壓縮操作,那麼Nginx會將結果資料進行壓後,在將資料返回給使用者端,在瀏覽器接收到nginx的請求,會先處理請求頭,發現有 壓縮協定,那麼就會判斷當前瀏覽器是否支援該協定,如果支援則會將數進行解壓的操作並資料展示給使用者。

開啟壓縮之後使用者是無感的,可以降低傳輸壓力,但是圖片和視訊就不建議壓縮了,因為後的大小變化不大,gzip是網路傳輸的壓縮的,需要使用者端支援,伺服器端也需要支援,將傳輸的資料進行壓縮,將傳輸資料變小,我們可以設定下,當然壓縮必越高,解壓縮和壓縮的時間更長,伺服器端壓力會大些。

三、Gzip壓縮

3.1 gzip介紹

Gzip是GNUzip的縮寫,最早用於UNIX系統的檔案壓縮。HTTP協定上的Gzip編碼是一種用來改進Web應用程式效能的技術,Web伺服器和使用者端(瀏覽器)必須共同支援Gzip。目前主流瀏覽器:Chrome、Firefox等都支援該協定,常見的伺服器:Apache、Nginx、IIS同樣支援Gzip。

Gzip的壓縮比率在3-10倍左右(純文字),可以大大節省伺服器的網路頻寬。在實際應用中,並不是對所有檔案進行壓縮,通常只壓縮靜態檔案(jscsshtml)。JPEG這類檔案用Gzip壓縮的不夠好,而且壓縮也是耗費CPU資源的。

那麼Gzip是如何進行壓縮的呢?簡單來說,Gzip壓縮是在一個文字檔案中找出類似的字串,並臨時替換他們,使整個檔案變小。這種形式的壓縮對Web來說非常合適,因為HTML和CSS檔案通常包含大量的重複字串,例如空格、標籤等。

3.2 gzip的使用

gzip模組是Nginx中內建的,所以不需要新增其他的預設,只要設定安裝好Nginx既可。

使用作用域: http , server , location

Nginx 如下設定

gzip on ;

  • 是否開啟壓縮。
  • 預設值:gzip off預設關閉

gzip_buffers 32 4k | 16 8k

  • 壓縮緩衝區大小。
  • 預設值 : gzip_buffers 32 4k | 16 8k

gzip_comp_level 1 ;

  • 壓縮等級 1-9 ,數位越大壓縮比越高。
  • 越小壓縮速度和解壓縮速度越快,壓縮佔比越小
  • 預設值 :gzip_comp_leve 1

gzip_http_version 1.1

  • 使用gzip 的最小的http版本。

gzip_min_length

  • 設定將被 gzip 壓縮的響應的最小長度。長度僅由 "Content-Length" 響應報頭欄位確定。

gzip_proxied 多選

  • 對於上游伺服器返回不同的head來決定是不是要進行壓縮,兩種常見的一種off一種any
  • 一般啟用cache的話都是已經進行過壓縮的所有可以規避一些細節
  • off 為不做限制。
  • 作為反向代理時,針對於上游伺服器返回的頭資訊進行壓縮。
  • expired - 啟用壓縮,如果header頭中包含 "Expires" 頭資訊
  • no-cache - 啟用壓縮,如果header頭中包含 "Cache-Control:no-cache" 頭資訊
  • no-store - 啟用壓縮,如果header頭中包含 "Cache-Control:no-store" 頭資訊
  • private - 啟用壓縮,如果header頭中包含 "Cache-Control:private" 頭資訊
  • no_last_modified - 啟用壓縮,如果header頭中不包含 "Last-Modified" 頭資訊
  • no_etag - 啟用壓縮 ,如果header頭中不包含 "ETag" 頭資訊
  • auth - 啟用壓縮 , 如果header頭中包含 "Authorization" 頭資訊
  • any - 無條件啟用壓縮。

gzip_vary on ;

  • 增加一個header ,適配老的瀏覽器 Vary : Accept-Encoding

gzip_types :

  • 哪些 mime型別的檔案進行壓縮。

gzip_disable :

  • 禁止哪些瀏覽器使用gzip。
  • 建議不要設定
  • 預設值 : gzip_disable 'msie6MSIE [4-6].MSIE 6.0'
location / {
  
  gzip off ;  # 開啟gzip壓縮
  gzip_buffers 32 4k ; # 設定緩衝區大小
  gzip_comp_level 5; # 設定壓縮等級 1-9 
  gzip_disable 'msie6MSIE [4-6].MSIE 6.0';  # 禁止哪些瀏覽器不使用壓縮
  gzip_http_version 1.1; # 設定壓縮所需要的最低的http版本。 
  gzip_min_length 20 ; # 設定響應的資料最小限制,在這個限制之後再回進行壓縮
  gzip_vary on ; # 增加一個header ,適用於老的瀏覽器 Vary:Accept-Encoding 
  gzip_proxied any; # 無條件啟動壓縮
  # 哪些mime型別的檔案進行壓縮 
  #gzip_types text/plain application/x-javascript text/css application/xml; 
  gzip_types
    text/xml application/xml application/atom+xml application/rss+xml application/xhtml+xml image/svg+xml
    text/javascript application/javascript application/x-javascript
    text/x-json application/json application/x-web-app-manifest+json
    text/css text/plain text/x-component
    font/opentype application/x-font-ttf application/vnd.ms-fontobject
    image/x-icon;
}

3.3 gzip的請求

當啟動了gzip,我們的請求到nginx伺服器上,nginx就已經給我們生產了response heard 但是資料還沒有生成,他也不知道具體資料有多大,因為nginx是非同步響應式請求,他一步一步來的,他先把header準備好然後請求內容去壓縮,最後將兩塊內容合併去壓縮,最後發過來,也就是因為非同步導致他不知道具體大小。

他是先將請求頭返回然後資料在慢慢讀。

----------------------------------響應體-------------------------------------------------
Connection: keep-alive
Content-Encoding: gzip # 結果啟動了gzip壓縮 
Content-Type: application/json # 響應結果 
Date: Mon, 13 Feb 2023 09:13:19 GMT
Keep-Alive: timeout=65
Server: nginx/1.20.2
Transfer-Encoding: chunked # 傳輸的格式這個對應的就是length,這個是他會傳送一個一個的包,當最後一個包是0表示傳輸結束
Vary: Accept-Encoding
 
 
 
------------------------------------請求頭-----------------------------------------------
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cache-Control: max-age=0
Connection: keep-alive
Host: 192.168.101.128
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36

注意:以上是動態壓縮就是所有的請求都會經歷一次壓縮,這個有一個致命的缺點就是不支援sendfile,sendfile是資料零拷貝,不會將資料載入到nginx,而是通過網路介面傳遞資料,但是一旦開啟了 gzip動態壓縮會導致sendfile失效,可以使用靜態壓縮。

在多層 Nginx時,建議和伺服器建立連線的Nginx進行開啟Gzip 就可以了,這樣就會支援gzip,在任意一臺開啟都是會開啟的gzip的 。

3.4 靜態壓縮

為什麼要使用靜態壓縮呢?

首先動態壓縮無法使用 sendfile 而靜態壓縮則完美的解決了這個問題。

靜態壓縮是一個互補或者說是一個擴充套件的功能,他可以把請求的這些資原始檔,我們可以預先的將內容進行壓縮成一個壓縮包。

首先靜態的資源一定是要比動態的資源要效率高,通過壓縮之後可以減少磁碟的大小,並且還可以節約網路的通道資源。

什麼是靜態壓縮

靜態壓縮不適合反向代理只適合資源伺服器,他可以把壓縮的檔案傳遞給使用者端,靜態壓縮就是在資源路徑下會有一個資原始檔還會有一個對應名稱的壓縮包。 並且Nginx會優先找壓縮包,直接通過 sendfile 將資料傳遞過去。

Nginx 將壓縮的檔案通過網路傳送過去,然後當瀏覽器接收到Nginx傳送的壓縮包檔案,並進行解壓縮的操作。他會在傳送給使用者端之前將壓縮包介面在傳送給使用者端。

3. 設定

該http_gzip_static_module模組允許傳送帶有“”副檔名的預壓縮檔案,.gz而不是常規檔案。預設情況下不構建此模組,應使用 --with-http_gzip_static_module 設定引數啟用它。這個模組沒有在預編譯的包裡,需要手動新增,這個模組的作用就是把壓縮包解壓開

with是內部模組,add是外部的模組。

首次安裝 nginx時使用

./configure --prefix==/usr/local/nginx --with-hhtp_gzip_static_module
make && make install

已經安裝過 nginx,對nginx使用者端升級時使用命令

./configure --prefinx==/usr/local/nginx --with-http_gzip_static_module

make不要make install 否則會覆蓋之前的檔案

在將 objs的nginx 程式拷貝到 /usr/local/nginx/sbin 下·,注意需要做好原 nginx 程式備份 。

語法 : gzip_static on | off | always;

作用:是否開啟靜態壓縮功能。

引數值:

  • on :開啟靜態壓縮,並會檢測瀏覽器是否支援,如果不支援則不會走靜態壓縮,
  • off :關閉靜態壓縮
  • always:是否使用靜態壓縮,無論瀏覽器是否支援靜態壓縮功能。
    • 這樣就會引發一個問題,如果使用者端不支援,就解不開 ,如果磁碟上沒有未壓縮的檔案預設會報404,可以配合 ngx_http_gunzip_module ,模組使用。
  • 預設值:gzip_static on
  • 適用於 :http、server、location

使用的需要將原生的資原始檔進行壓縮 ,壓縮成 xxx.gz的檔案

cd /usr/local/nginx/html 
gzip * 

注意:開啟之後預設就會先存取 .gz 的檔案了,如果不支援 靜態壓縮則會存取 正常檔案,如果沒有正常的檔案只有 .gz 那麼就會報錯 。

4. nginx_http_gunzip_module 模組

這個模組是配合 gzip_static always時使用的 ,因為 當設定程 always 時,所有的請求會都進行找壓縮檔案,在檔案存不存在或者說瀏覽器支不支援 靜態壓縮,nginx都會將靜態壓縮檔案返回給瀏覽器,如果瀏覽器不支援的話會導致檔案解不開,也就是 404 。

這個模組它沒有在預編譯的包裡,需要手動新增,這個模組的作用就是把靜態的壓縮包解壓開,他會在傳送給使用者端之前將壓縮包介面在傳送給使用者端,它相當於是一層攔截器,它的作用就是可以把原始檔進行壓縮,我們可以把原始檔進行刪除了,節省磁碟空間,但是一般會用到。

注意 : with 是內部 、 add 是外部的

安裝命令 :

./configure --prefix=/usr/local/nginx --add-module=/tools/nginx-sticky --with-http_gzip_static_module --with-http_gunzip_module

make

如果是替換的話,則將這個檔案中的這個檔案 cp 到 nginx的安裝目錄下的 sbin

移動命令:

 cp /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.old2
 
 cd /tools/nginx/objs 
 mv nginx /usr/local/nginx/sbin/

這裡沒有gzip,但也沒有 context-length 因為nginx需要把檔案解壓縮,他也不知道具體檔案有多大,這個 gzip_static 適用場景 :在作為cdn伺服器或者 cdn上游伺服器檔案儲存伺服器時,我們就可以把本地原始檔案刪了,只展示zip 包,把解壓縮的壓力丟棄給使用者端 , 同時可以把本地壓縮等級,提高不是 gzip的壓縮等級 ,經常高配存取的一些頁面 css js ,也可以通過 static壓縮。

靜態壓縮 響應結果會有 Context-Encoding : gzip 、Conten-Length:392 有展示 context-length 表示他開啟了靜態壓縮,預壓縮直接返回zip包 沒有原始檔 ,1.速度快,2節省伺服器資源。

四、Brotli

Brotli 是 Google 推出的開源壓縮演演算法,通過變種的 LZ77 演演算法、Huffman 編碼以及二階文字建模等方式進行資料壓縮,與其他壓縮演演算法相比,它有著更高的壓縮效率,效能也比我們目前常見的 Gzip 高17-25%,可以幫我們更高效的壓縮網頁中的各類檔案大小及指令碼,從而提高載入速度,提升網頁瀏覽體驗。需要說明的是 Brotli 壓縮只在 https 下生效,因為 在 http 請求中 request header 裡的 Accept-Encoding: gzip, deflate 是沒有 br 的。

Brotli 如此高的壓縮比率,得益於其使用一個預定義的字典,該字典包含超過 13000 個來自文字和 HTML 檔案的大型語料庫的常用字串,預定義的演演算法可以提升較小檔案的壓縮密度,而壓縮與解壓縮速度則大致不變。

Brotli 憑藉它優異的壓縮效能迅速佔領了市場,從下圖可以看到,除了 IE 和 Opera Mini 之外,幾乎所有的主流瀏覽器都已支援 Brotli 演演算法,因此處於資源佔用的考慮,比如說流量,建議啟用:

Brotil 規範由 Google 員工 Jyrki Alakuijala 和 Zoltan Szabadka 於 2013-2016開發,並伴隨著規範的倆個作者Evgenii Kuliuchniko 和 Lode Vandevenne共同開發的參考實現,後者之前開發了谷歌的zopfli在2013年重新實現了收縮 /gzip 壓縮格式。與zopfli不同,後者是對現有資料格式規範的重新實現,Brotli 是一種新的資料格式,並允許作者進一步提高壓縮比。

4.1 Brotli 概述

Brotli 的編碼器提供了 12 個質量級別 (從 0 到 11)。它們是壓縮速度換取壓縮效率的壓縮模式:更高質量的幾倍速度較慢,但會產生更好的壓縮比。

一個 Brotli 壓縮檔案由 元塊(meta-blocks)集合組成。每個元塊最多可容納 16 MiB,由倆部分組成:一個 資料部分(data part),它儲存 LZ77 壓縮的放入快,以及一個 標題(header),每個塊的壓縮遵循經典的 ①LZ77 壓縮方案並由 ②計算具有良好的LZ77解析和計算 LZ 短語的簡潔編碼這倆個主要階段組成。

它效率高是因為內建了 n多個字典,包含都是一些常見的檔案檔案 css 、js 等等一些標籤,如果我們將這些標籤歸類生成一個字典之後,我們就可以按照序號去解壓這個檔案了。

並且它在 Nginx 中話是可以和 Gzip 共存,開啟了Brotli 不會導致 Gzip失效,如果瀏覽器支援brotli 那麼優先使用 Brotli ,不支援在使用 Gzip。

4.2 Brotli 的安裝

--add-dynamic-module表示動態的引入模組在組態檔中還需要單獨加入 load_module path/xxx

官網

下載 倆個專案

解壓縮

  • brotli-1.0.9 是 brotli 演演算法模組,需要先解壓。
    • tar -zxvf brotli-1.0.9.tar.gz
  • ngx_brotli-1.0.0rc 是nginx的 brotli的模組。這模組裡需要引入 brotli 演演算法模組
    • tar -zxvf ngx_brotli-1.0.0rc.tar.gz

接下來講 brotli 的內容全部 複製到 ngx_brotli 的 deps/brotli/目錄

  • cd /tools/brotli-1.0.9
  • cp -r * /tools/ngx_brotli-1.0.0rc/deps/brotli/

模組化編譯 :

./configure --with-compat --add-dynamic-module=/tools/ngx_brotli-1.0.0rc --prefix=/usr/local/nginx/

--add-dynamic-module=brotli目錄

載入所有的壓縮模組

./configure --with-compat --add-dynamic-module=/tools/ngx_brotli-1.0.0rc --prefix=/usr/local/nginx/ --add-module=/tools/nginx-sticky --with-http_gzip_static_module --with-http_gunzip_module

make && make install

下載的兩個模組 拷貝到 /usr/local/nginx/modules/

首先在 /usr/local/nginx建立一個modules資料夾 mkdir modules

mv ngx_http_brotli_filter_module.so ngx_http_brotli_static_module.so /usr/local/nginx/modules/

最後將新編譯的 nginx 啟動程式複製到 /usr/local/nginx/sbin下 做好之前程式複製。

  • cp /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.oid3
  • mv /tools/nginx-12.0/objs/nginx /usr/local/nginx/sbin/

在組態檔中動態載入模組

load_module "/usr/local/nginx/modules/ngx_http_brotli_filter_module.so";
load_module "/usr/local/nginx/modules/ngx_http_brotli_static_module.so";

4.3 設定選項

具體的設定選項可以檢視GitHub: https://github.com/google/ngx_brotli

brotli的設定可以參考Gzip的設定,幾乎一致。

brotli

  • 語法:brotli on | off
  • 預設值 :brotli off
  • 適用於: http、server、location、if
  • 作用:開啟或者禁用brotli 壓縮功能。

brotli_static

  • 語法:brotli_static on | off | always
  • 預設值:brotli_static off
  • 適用於:http、server、location
  • 作用:brotli 也是支援預先壓縮檔案,啟用或禁用檢查是否存在帶擴充套件名的預壓縮檔案.br 。使用該always值,在所有情況下都使用預壓縮檔案,而不檢查使用者端是否支援它。

brotli_types

  • 語法:brotli_types <mime_type> [...]
  • 預設值:brotli_types text/html
  • 適用於: http、server、location
  • 作用:指定哪些資源型別需要進行壓縮操作,特殊值*匹配任何 MIME型別。

brotli_buffers

  • 語法:brotli_buffers <number> <size>
  • 預設值: 32 4k | 16 8 k
  • 適用於: http、server、location
  • 作用:設定壓縮緩衝區大小,最新版本以及棄用了 。

brotli_comp_level

  • 語法:brotli_comp_level <level>
  • 預設值 :6'
  • 適用於 : http、server、location
  • 作用 : 設定即時壓縮 Brotli 質量(壓縮)level。0可接受的值在從到 的範圍內11。

brotli_window

  • 語法:brotli_window <size>
  • 預設值 : 512k
  • 適用於 :http、server、 location
  • 作用:設定 Brotli 視窗size。可以比作是一個桌子,將要壓縮的檔案同時放在這個桌子上,這個桌子上可以放多少檔案的大小,這個值也不越大越好,他比較佔記憶體,值增加建議是2的倍數,可接受的值為1k, 2k, 4k, 8k, 16k, 32k, 64k, 128k, 256k, 512k, 1m, 2m,和4m。8m 16m

brotli_min_length

  • 語法:brotli_min_length <length>
  • 預設值:20
  • 適用於: http、server、location
  • 作用:指定進行壓縮的檔案最小的長度,如果小於這個值則不壓縮。
#載入動態模組 
load_module "/usr/local/nginx/modules/ngx_http_brotli_filter_module.so";
load_module "/usr/local/nginx/modules/ngx_http_brotli_static_module.so";
worker_processes  1;
events {
    worker_connections  1024;
}
 
http {
    server {
    listen       80;
    server_name  localhost;
        location  / {
          #brotli設定 
          brotli on;  # 開啟 壓縮
        brotli_static on; # 是否開啟預先壓縮,開啟之後就會 .br的壓縮包
          brotli_comp_level 6; # 壓縮等級
          brotli_buffers 16 8k; # 緩衝區大小 ,已經啟用 
          brotli_min_length 20; # 壓縮時檔案最小限制 
          # 對哪些mime.types型別進行壓縮
          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;
    
          }
  }
}

4.4 brotli 測試

因為預設 brotli 是必現 https 請求才能使用的,因為 http的請求 請求頭的 Accept-Encoding 是沒有 br的,所以伺服器是無法知道使用者端可以使用的。

測試方案:

使用 linux 的 curl 命令 :

curl -H 'Accept-Encding : br' -I 192.168.101.128/index.html
[root@localhost sbin]# curl -H Accept-Encoding:br  -I http://192.168.101.128/static_page.html
HTTP/1.1 200 OK
Server: nginx/1.20.2
Date: Fri, 17 Feb 2023 08:11:05 GMT
Content-Type: text/html
Last-Modified: Fri, 17 Feb 2023 03:28:14 GMT
Connection: keep-alive
Keep-Alive: timeout=65
Vary: Accept-Encoding
ETag: W/"63eef44e-31"
Content-Encoding: br
[root@localhost sbin]# curl  -I http://192.168.101.128/static_page.html
HTTP/1.1 200 OK
Server: nginx/1.20.2
Date: Fri, 17 Feb 2023 08:11:54 GMT
Content-Type: text/html
Last-Modified: Fri, 17 Feb 2023 03:28:14 GMT
Connection: keep-alive
Keep-Alive: timeout=65
Vary: Accept-Encoding
ETag: W/"63eef44e-31"

到此這篇關於Nginx 請求壓縮的實現(動態壓縮,靜態壓縮)的文章就介紹到這了,更多相關Nginx 請求壓縮內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com