Nginx 用分片提示缓存效率基于range协议
slice 模块功能:通过range协议将大文件分解多个小文件,更好的用缓存为客户端的range协议服务

1.1 Nginx的Range回源、ngx_http_slice_module模块、–with-http_slice_module参数
Nginx的ngx_http_slice_module模块是用来支持Range回源的。
ngx_http_slice_module从Nginx的1.9.8版本开始有的。
启用ngx_http_slice_module模块需要在编译Nginx时,加参数–with-http_slice_module。
1.2 curl指定Range范围
-r 指定Range的范围
1.3 HTTP 206
HTTP的Range请求,成功返回时的状态码是206。
1.4 架构
缓存、源站
用户向缓存请求URL,缓存进行Range回源。
模块:–with-http_slice_module

二、缓存配置文件
例子1

#user  nobody;
worker_processes  1;

events {undefined
    worker_connections  1024;
}


http {undefined
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  logs/access.log  main;

    sendfile        on;

    keepalive_timeout  65;

    #cache
    proxy_cache_path /data/cache
                keys_zone=cache_my:100m
                levels=1:1
                inactive=12d
                max_size=200m;

    server {undefined
        listen       80;
        server_name  localhost;

        location / {undefined
                #slice
                slice 1k;
                proxy_cache cache_my;
                proxy_cache_key $uri$is_args$args$slice_range;
                add_header X-Cache-Status $upstream_cache_status;
                proxy_set_header Range $slice_range;
                proxy_cache_valid 200 206 3h;
                proxy_pass http://192.168.175.135:80;

                proxy_cache_purge PURGE from 127.0.0.1;
        }
    }
}

例子2
改进 一
如果是一个大文件下载,请求的是文件的一部分,下载的却是整个文件,势必会造成流量暴增,下载很慢,如果我们想要 nginx upstream 也是用range请求到后端,并缓存这部分内容到缓存目录,怎么配置呢?

请求Range --> nginx proxy cache (upsteam range) --> 下载服务
(缓存文件的一部分)

还是上面的 nginx配置,把 no range 部分替换成

proxy_cache_key $host&uri&is_args&args$http_range;
proxy_set_header Range $http_range;
proxy_set_header If-Range $http_if_range;
proxy_cache_valid 200 206;

测试,没好用,range请求文件可以下载,但是无法缓存,还需要看看怎么回事 !!!

改进二
如果只想对 非Range 的请求缓存,对range的下载请求不做缓存,那么配置中no range 部分替换成

proxy_cache_key $host&uri&is_args&args;  #key中不缓存range信息
proxy_set_header Range $http_range;
proxy_set_header If-Range $http_if_range;
proxy_no_cache $http_range $http_if_range;  #加了一个配置
proxy_cache_valid 200;

例子3

http {  
    include       mime.types;  
    default_type  application/octet-stream;  
    sendfile        on;  
    keepalive_timeout  65;  
  
    proxy_cache_path /tmp/nginx/cache levels=1:2 keys_zone=cache:100m;  
    server {  
        listen       8087;  
        server_name  localhost;  
        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_set_header Range $http_range;  
            proxy_pass http://127.0.0.1:8080;  
  
        }  
        error_page   500 502 503 504  /50x.html;  
        location = /50x.html {  
            root   html;  
        }  
    }  
}

不测不知道,一侧吓一跳,这俨然是一个杀手级的特性。
首先,如果不带 Range 请求,后端大文件在本地 cache 时,会按照配置的 slice 大小进行切片存储。

其次,如果带 Range 请求,则 Nginx 会用合适的 Range 大小(以 slice 为边界)去后端请求,这个大小跟客户端请求的 Range 可能不一样,并将以 slice 为大小的切片存储到本地,并以正确的206响应客户端。

注意上面所说的,Nginx 到后端的 Range 并不一定等于客户端请求的 Range,因为无论你请求的Range 如何,Nginx 到后端总是以 slice 大小为边界,将客户端请求分割成若干个子请求到后端,假设配置的 slice 大小为1M,即1024字节,那么如果客户端请求 Range 为0-1023范围以内任何数字,均会落到第一个切片上,如果请求的 Range 横跨了几个 slice 大小,则nginx会向后端发起多个子请求,将这几个 slice 缓存下来。而对客户端,均以客户端请求的 Range 为准。如果一个请求中,有一部分文件之前没有缓存下来,则 Nginx 只会去向后端请求缺失的那些切片。

由于这个模块是建立在子请求的基础上,会有这么一个潜在问题:当文件很大或者 slice 很小的时候,会按照 slice 大小分成很多个子请求,而这些个子请求并不会马上释放自己的资源,可能会导致文件描述符耗尽等情况。

小结
总结一下,需要注意的点:

该模块用在 proxy_cache 大文件的场景,将大文件切片缓存
编译时对 configure 加上 –with-http_slice_module 参数
$slice_range 一定要加到 proxy_cache_key 中,并使用 proxy_set_header 将其作为 Range 头传递给后端
要根据文件大小合理设置 slice 大小

参考

https://pureage.info/2015/12/10/nginx-slice-module.html

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;
}

下游服务器代码示列

server {
        listen       8080;
        server_name  shop**.com.cn;
        location / {
           root html;
           proxy_cache two;
           proxy_cache_valid 200 206 1m;
           proxy_pass http://192.168.0.51:8012; #代理到上游服务器
        }
}

上游服务器代码示列 在html里有个大文件

server {
                listen 8012;
                default_type text/plain;
                root html;
                location / {

                }
}

请求示列

curl -r 10000-10010 http://shop**.com.cn:8080/step -I  //-r 表示启用range

返回示列

HTTP/1.1 206 Partial Content
Server: openresty/1.13.6.2
Date: Fri, 15 Mar 2019 10:07:02 GMT
Content-Type: text/plain
Content-Length: 11 #获取的实际数量 因为 10000-10010 长度是11
Connection: keep-alive
Last-Modified: Fri, 08 Mar 2019 02:13:42 GMT
Vary: Accept-Encoding
ETag: "5c81cfd6-281c558"
Content-Range: bytes 10000-10010/42059096 #这里会看到总量与取量

但是有个问题,如果用户并发请求缓存的话会影响性能 一般用多线程并且使用range协议的话

proxy_cache_path data/tmpcache levels=2:2 keys_zone=two:10m loader_threshold=300
                     loader_files=200 max_size=200m inactive=1m;
  server {
        listen       8080;
        server_name  shop**.com.cn;
        location / {

        root html;
                slice 1m;
                proxy_cache_key $uri$is_args$args$slice_range;
                proxy_set_header Range $slice_range; #这里必须要加range协议到头部 而且需要加范围值
                proxy_cache two;
                proxy_cache_valid 200 206 1m;
                proxy_pass http://192.168.0.51:8012;
    }
}