一、為什么需要 Slice?
在 NGINX 反向代理或 CDN 場景中,大文件(視頻、軟件包、鏡像等)常因單體體積過大而令緩存命中率低、回源代價高。
ngx_http_slice_module
通過把一次完整響應拆分成 固定大小的字節塊(Slice),讓各塊分別緩存,從而帶來三大收益:
-
更高緩存命中率
- 客戶端斷點續傳、并發 Range 請求只命中需要的分片,無須整文件回源。
-
回源壓力小
- 回源服務器可串流輸出,對下游節點按塊供給,避免一次性讀取整文件。
-
快速失敗與熱區
- 若分片出現損壞或更新,僅重拉對應 Slice,其他分片繼續復用緩存。
二、模塊啟用
ngx_http_slice_module
默認未編譯。必須在編譯 NGINX 時加入:./configure --with-http_slice_module \--with-http_ssl_module # 其他模塊 make && sudo make install
驗證是否編譯成功:
nginx -V 2>&1 | grep --color http_slice
三、核心概念
名稱 | 說明 |
---|---|
Slice | 一個固定大小的字節塊(例如 1 MiB),每個塊通過子請求(subrequest)回源并緩存。 |
$slice_range | 模塊自動生成的變量,格式形如 bytes=0-1048575 ,指明本子請求需要的區間;需作為 Range 頭傳遞給上游。 |
狀態碼 206 | 分片請求回源時,上游需返回 206 Partial Content 并帶 Content-Range ,NGINX 緩存到本地。 |
子請求 (subrequest) | NGINX 在后臺對每個 Slice 發起獨立請求;與 proxy_cache_background_update 等子請求并存時有已知問題(見后文)。 |
四、最小可用配置(一步一步)
假設:
- 回源服務
http://localhost:8000/
存放大文件; - 目標:把每個響應切成 1 MiB 切片并緩存。
http {proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=cache:100m inactive=1h;server {listen 80;location / {# 1. 開啟分片,單位可用 k/m/gslice 1m;# 2. 啟用緩存proxy_cache cache;proxy_cache_valid 200 206 1h;# 3. 把分片區間加入緩存 key,保證不同片段獨立緩存proxy_cache_key $uri$is_args$args$slice_range;# 4. 告訴回源取哪段字節proxy_set_header Range $slice_range;# 5. 回源proxy_pass http://localhost:8000;}}
}
流程說明:
- 首個請求 → NGINX 判斷需切片,先取
slice=0~1048575
。 - cache miss → 向回源帶
Range: bytes=0-1048575
,獲得206
,緩存。 - 后續切片 → 繼續子請求;未命中則回源、命中則直返。
- 客戶端端網速變化 → 支持斷點續傳;若斷線后重連,只拉缺失部分,命中率高。
五、可調指令
5.1 slice size;
-
size:每片大小,可寫
256k | 1m | 4m
等; -
0(默認)關閉切片。
-
建議:
- 小文件 < size -> 不切片;
- 過小會導致文件句柄過多,過大會降低命中率,常用 512 k ~ 2 m。
5.2 $slice_range
無需顯式定義,模塊自動按 slice
和當前偏移生成。例如:
bytes=1048576-2097151
務必用 proxy_set_header Range $slice_range
傳遞給上游。
六、進階技巧
6.1 HTTPS 回源 + Range
若回源是 HTTPS,上游同樣須支持分段下載;否則 NGINX 會回退整文件。
proxy_pass https://backend.example.com;
proxy_set_header Range $slice_range;
6.2 限制并發子請求
過多并發會給回源帶來壓力,可在 proxy_cache_lock
/ limit_conn
等模塊配合限流。
proxy_cache_lock on; # 只有首個分片回源,其余等待,防止擊穿
limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn perip 10; # 每 IP 最多 10 并發
6.3 與 Range/Head 兼容
客戶端自己發 Range(斷點續傳)時,Slice 會在原有 Range 內繼續切分,返回多片合并結果,對客戶端透明。
6.4 NJS 動態調整 Slice
可用 set $slice_size ...
+ slice $slice_size;
按不同 URI / MIME 策略動態調整分片大小。
七、已知問題與避坑
場景 | 問題表現 | 解決建議 |
---|---|---|
Background Cache Update | 使用 proxy_cache_background_update on; 時,不支持 Range,可能整文件回源 | 避免在同一 location 打開該特性;或使用主動刷新腳本 |
過小 Slice (<32k ) | fd 數暴增、內存占用高 | Slice ≥ 256k;確保 worker_rlimit_nofile 足夠 |
回源不支持 Range | 上游返回 200 整文件,Slice 無意義 | 確認回源支持 Accept-Ranges: bytes headers |
ETag 變化 | 不同分片用不同 ETag 導致緩存擊穿 | 統一回源 ETag 或禁用 proxy_ignore_headers ETag; |
八、監控 & 調試
- 查看緩存:
ls -l /data/nginx/cache
,每片生成獨立緩存文件。 - 日志標記:在
log_format
中加入$slice_range
、$upstream_status
便于排查:
log_format slice '$remote_addr $uri $status ''range=$slice_range up=$upstream_status';
access_log /var/log/nginx/slice.log slice;
-
性能指標:
proxy_cache_hit
,miss
connections_active
,reading
,writing
- 磁盤 IO
九、場景實戰
9.1 大文件下載(ISO、固件)
slice 2m; # 較大分片減少文件數
proxy_cache_valid 200 206 12h; # 長時間緩存
9.2 HLS/DASH 點播
分片文件本就小,可關閉切片,或僅對 .mp4
大文件切片:
location ~ \.mp4$ {slice 1m;...
}
9.3 鏡像倉庫代理
鏡像層 (layer) 可達數百 MB,開啟切片后可極大提高復用率。
十、總結
-
一句話:
ngx_http_slice_module
通過“分片 + 緩存”讓大文件交付更高效。 -
必做:
- 編譯開啟
--with-http_slice_module
- 設置
slice
大小 + 緩存 key 中加入$slice_range
- 將
$slice_range
作為Range
頭傳遞 - 緩存中允許狀態碼
206
- 編譯開啟
-
可選:結合
proxy_cache_lock
、limit_conn
、自定義session_log
等做進一步優化。
掌握上述配置與注意事項后,你就可以讓 NGINX 在大文件分發、CDN 邊緣緩存、鏡像倉庫等場景下發揮極致性能,顯著降低回源壓力與帶寬消耗。祝你使用順利,緩存命中率節節攀升!