一、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回源。

二、缓存配置文件

例子1

#user  nobody;
 worker_processes  1;events {
     worker_connections  1024;
 } http {
     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 {
         listen       80;
         server_name  localhost;        location / {
                 #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