• 正文
  • 相关推荐
申请入驻 产业图谱

Nginx | slice 模块,实现上游大文件“化整为零”缓存

01/09 10:55
140
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

大家好,我是 WeiyiGeek,一名深耕安全运维开发(SecOpsDev)领域的技术从业者,致力于探索DevOps与安全的融合(DevSecOps),自动化运维工具开发与实践,企业网络安全防护,欢迎各位道友一起学习交流、一起进步 ,若此文对你有帮助,一定记得点个关注⭐与小红星❤️或加入到作者知识星球『 全栈工程师修炼指南』,转发收藏学习不迷路  。

Nginx 使用 slice 模块实现大文件分片缓存,提高下载效率

描述:上一文《Nginx | ngx_cache_purge 模块:实现清除特定上游服务(后端)响应缓存条目》,介绍了利用第三方插件 ngx_cache_purge 实现了清除指定缓存的功能,本节将介绍如何使用 Nginx 内置的模块 ngx_http_slice_module 实现大文件分片缓存,在使用 Nginx 作为反向代理当上游响应大文件(例如,视频文件、压缩文件、文本文件)时,用于提高缓存效率。

温馨提示:若文章代码块中存在乱码或不能复制,请联系作者,也可通过文末的阅读原文链接,加入知识星球中阅读,原文链接:https://articles.zsxq.com/id_6hpaidhf5l5s.html

模块介绍

ngx_http_slice_module 模块(1.9.8)是一个过滤器,其提供了更有效的大响应缓存,它将一个请求拆分为子请求,每个子请求返回一定范围的响应,简单来说就是,它将一个大文件响应拆分成多个小块响应,并对每个块进行缓存。这样可以减少对磁盘的读写次数,提高大文件的传输效率,这样便可使得可以利用某些下载工具并行下载这些小块,从而提高大文件的下载速度。

为了方便大家理解它是如何减少对上游服务器的压力,提高大文件的传输效率,下面利用一张图来讲解 slice 模块运行流程,如下图所示:

首先,客户端发起一个请求 100 字节,偏移量从 150 开始,例如:GET /video.mp4 HTTP/1.1 Range = 150-249 字节的数据。

其次,假设 Nginx 配置了切片大小为 100 字节,在 Nginx 后台进程中将会向后端请求两次,一次请求 100-199 段,另一次请求 200-299 段。

然后,Nginx 分布将这些请求到段缓存到磁盘上的 /cache/XYZ 和 /cache/ABC 缓存文件中。

最后,将它们组合成完整的响应返回给客户端,此后,如果客户端再次请求相同范围的字节数据时,可以直接从缓存中读取,无需再向后端服务器发送请求。

weiyigeek.top-slice 模块运行流程图

参考文档: https://nginx.org/en/docs/http/ngx_http_slice_module.html

注意:默认情况下不会构建此模块,应使用 --with-http_slice_module 配置参数启用此模块,其次是该模块在后台缓存更新等子请求中无法正常工作,即使用 proxy_cache_background_update 指令此模块将无法工作,例如:

# 构建脚本 Makefile
./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --sbin-path=/usr/sbin/nginx --conf-path=/usr/local/nginx/conf/nginx.conf --pid-path=/usr/local/nginx/nginx.pid --error-log-path=/var/log/nginx/logs/error.log --http-log-path=/var/log/nginx/logs/access.log --lock-path=/var/run/nginx.lock --modules-path=/usr/local/nginx/modules --with-http_stub_status_module --with-http_realip_module --with-http_v2_module --with-http_ssl_module --add-module=/usr/local/src/ngx_cache_purge --with-http_slice_module --with-cc-opt=-O2 --with-compat

# 编译安装
make -j$(nproc) && make install

指令参数

该模块只有一个指令:slice,用于定义每个切片大小,影响着每个子请求返回的响应大小,特别注意:太低的值可能会导致过多的内存使用和打开大量的文件。

Syntax: slice size;
Default: slice 0;
Context: http, server, location

# 参数说明:
  0 表示禁用切片,即不启用该模块。
  size 表示切片大小,默认单位为字节,也支持使用 K, M 等单位,例如:1024K 或 1M。

# 简单示例:例如将响应被分割为1 MB的可缓存切片。
location / {
  slice             1m;
  proxy_cache       cache;
  proxy_cache_key   $uri$is_args$args$slice_range;
  proxy_set_header  Range $slice_range;
  proxy_cache_valid 200 206 1h;
  proxy_pass        http://localhost:8000;
}

另外,其内置了一个$slice_range变量,用于表示当前切片的范围,如 bytes=0-1048575,HTTP 字节范围 rfc7233 标准,

该变量的作用是为让子请求返回所需的范围,$slice_range 变量应该作为 Range 请求头字段传递给代理服务器。如果启用了缓存,则应将 $slice_range 添加到该高速缓存键中,并应启用对状态码为206的响应的缓存,这一点在上面的简单示例中可用查看到具体使用。

实例演示

步骤 01.首先,在 Nginx 主机中准备大一些的文件(如,视频文件、压缩文件、文本文件)然后监听一个 8011 端口,利用 root 指令指向静态资源目录,用于模拟上游服务。

# 测试文件
$ mkdir /usr/local/nginx/html/slice
$ ls -lah /usr/local/nginx/html/slice
total 116M
drwxr-xr-x  2 root root 4.0K Jan  7 16:27 .
drwxr-xr-x 14 root root 4.0K Jan  7 16:25 ..
-rw-r--r--  1 root root  59M Mar 23  2024 202403192224.mp4
-rw-r--r--  1 root root  58M Jan  7 16:27 202403192224.zip

# 模拟上游服务器其监听端口为8011
tee server.conf <<'EOF'
server {
  listen 8011;
# 任意主机名
  server_name _;
# 设置字符集为utf-8
  charset utf-8;
# 设置默认响应类型为二进制流数据
  default_type application/octet-stream;
# 根目录
  location / {
    root  /usr/local/nginx/html/slice;
    index index.html;
  }
}
EOF

# 重启 Nginx 后使用浏览器测试文件是否可以正常访问
http://10.20.172.214:8011/202403192224.mp4

weiyigeek.top-测试准备的视频大文件图

步骤 02.在 Nginx 服务器上配置缓存路径以及反向代理,并启用分片缓存策略。

tee test.conf <<'EOF'
# 定义缓存路径,为 data01 缓存区域分配10MB内存空间,加载缓存索引文件,并设置最大内存使用限制为128MB,删除10分钟内不活跃的缓存条目。
proxy_cache_path /usr/local/nginx/cache levels=2:2 keys_zone=data01:10m loader_threshold=300 loader_files=200 max_size=128m inactive=10m;

# 虚拟主机配置,反向代理到上游服务器组
server {
  listen 80;
  server_name test.weiyigeek.top;
  charset utf-8;
  default_type text/html;

# 启用 HTTP/2 支持
  http2 on;

# 日志文件
  access_log /var/log/nginx/test.log main;
  error_log /var/log/nginx/test.err.log debug;

  location / {
    proxy_pass http://10.20.172.214:8011;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    # 启用长连接
    proxy_set_header Connection "";
    proxy_http_version 1.1;

    # 设置切片大小为1MB,这将把响应分割为可缓存的1MB大小的切片
    slice 1m;
    # 变量作为 Range 请求头字段传递给代理服务器
    proxy_set_header Range $slice_range;

    # 启用缓存,指定缓存区域为 data01
    proxy_cache data01;
    # 自定义缓存KEY
    proxy_cache_key $uri$is_args$args$slice_range;

    # 设置缓存有效时间,对于200和206状态码的响应设置为1小时
    proxy_cache_valid 200 206 1h;

    # 自定义响应头,用于验证上游缓存状态
    add_header X-Cache-Status $upstream_cache_status;
  }
}
EOF

步骤 03.验证重启 Nginx 服务,使用 curl 命令验证分片访问视频文件。

nginx -t && nginx -s reload

# 第一次请求
$ curl -I -r 50000001-50001000 http://test.weiyigeek.top/202403192224.mp4
HTTP/1.1 206 Partial Content
Server: nginx/1.29.0
Date: Wed, 07 Jan 2026 09:07:57 GMT
Content-Type: video/mp4
Content-Length: 1000   # 关键点,只取了 1000 byte
Connection: keep-alive
Last-Modified: Sat, 23 Mar 2024 15:43:55 GMT
ETag: "65fef8bb-3a83f2b"
X-Cache-Status: MISS   # 关键点,首次请求未被命中
Content-Range: bytes 50000001-50001000/61357867  # 关键点,响应范围

# 第二次请求
$ curl -I -r 50000001-50001000 http://test.weiyigeek.top/202403192224.mp4
HTTP/1.1 206 Partial Content
Server: nginx/1.29.0
Date: Wed, 07 Jan 2026 09:08:15 GMT
Content-Type: video/mp4
Content-Length: 1000
Connection: keep-alive
Last-Modified: Sat, 23 Mar 2024 15:43:55 GMT
ETag: "65fef8bb-3a83f2b"
X-Cache-Status: HIT # 关键点,已命中缓存
Content-Range: bytes 50000001-50001000/61357867

# 第三次请求(同样是命中缓存)
$ curl -I -r 50000001-50001000 http://test.weiyigeek.top/202403192224.mp4

# 查看缓存目录
$ tree /usr/local/nginx/cache/
$ ls -al /usr/local/nginx/cache/3f/3f/3e72a4edcc006671dc4c19f9ac043f3f

weiyigeek.top-验证slice分片缓存图

步骤 04.查看日志文件,可以发现反向代理未启用 slice 时,请求的数据是该文件的大小;而启用后,请求的数据是 1m 大小,并且在缓存启用之后,后续的请求相同的 range 的数据时都是直接从缓存中获取数据。

# 8011 端口日志
$ tail -f /var/log/nginx/logs/access.log
# 反向代理未启用 slice 时,请求的数据是该文件的大小
10.20.172.103 - - [07/Jan/2026:16:32:44 +0800] "GET /202403192224.mp4 HTTP/1.1" 200 61357867 "-""Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:146.0) Gecko/20100101 Firefox/146.0"
# 反向代理启用 slice 时,请求的数据是 1m 大小
10.20.172.214 - - [07/Jan/2026:17:07:57 +0800] "GET /202403192224.mp4 HTTP/1.1" 206 1048576 "-""curl/8.4.0"

# 80 端口日志
$ tail -f /var/log/nginx/test.log
10.20.172.214 - - [07/Jan/2026:17:07:57 +0800] "HEAD /202403192224.mp4 HTTP/1.1" 206 0 "-""curl/8.4.0""-"
10.20.172.214 - - [07/Jan/2026:17:08:15 +0800] "HEAD /202403192224.mp4 HTTP/1.1" 206 0 "-""curl/8.4.0""-"
10.20.172.214 - - [07/Jan/2026:17:10:48 +0800] "HEAD /202403192224.mp4 HTTP/1.1" 206 0 "-""curl/8.4.0""-"

# 请求相同 range 范围内的数据时都是直接从缓存中获取数据。
$ curl -I -r 50000101-50001000 http://test.weiyigeek.top/202403192224.mp4
HTTP/1.1 206 Partial Content
Server: nginx/1.29.0
Date: Wed, 07 Jan 2026 09:27:26 GMT
Content-Type: video/mp4
Content-Length: 900
Connection: keep-alive
Last-Modified: Sat, 23 Mar 2024 15:43:55 GMT
ETag: "65fef8bb-3a83f2b"
X-Cache-Status: HIT
Content-Range: bytes 50000101-50001000/61357867  # 之前是 50000001-50001000/61357867

至此, 作者介绍 slice 模块并演示在 Nginx 反向代理利用 slice 分片缓存的策略实践,最后在提及一点,如果客户端使用或者支持断点续传,多线程下载含有range协议的场景时 slice 模块是非常有用的。

 

加入:作者【全栈工程师修炼指南】知识星球

相关推荐