[Nginx] proxy cache 中对带有 Range header 请求的处理

media 文件下载服务需要一层cache,使用的是 Nginx 的 proxy_cache 模块,文件下载常见的一个需求就是要使用 Range 这个请求header来下载文件的一部分。下面就是测试 proxy_cache 模块,对这种请求的处理。

思考

前提

  • 下载服务本身支持range请求

第一种情况:

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

第二种情况

请求Range --> nginx proxy cache --> 下载服务
               (缓存文整个文件)

测试

  • macos
  • openresty 1.9.7
  • curl

nginx 配置文件

# source site
server {
    listen 10010;
    location / {
        index  index.html index.htm;
    }
}

# cache site
proxy_cache_path /tmp/ngcache levels=1:2 keys_zone=cache_test:2m inactive=30m max_size=10240m;

server {
    listen 10009;
    location / {
        proxy_cache cache_test;

        # no range
        proxy_cache_key $host&uri&is_args&args;
        proxy_cache_valid 200;

        add_header X-Proxy-Cache $upstream_cache_status;
        proxy_set_header Host $host;
        proxy_pass http://127.0.0.1:10010;
    }
}
  • 端口 10009,缓存服务
  • 端口 10010,下载服务,也叫做源站

使用带有 Range 的请求访问源站,保证源站支持这种方式

$ curl -r 0-1 -i http://127.0.0.1:10010

HTTP/1.1 206 Partial Content
Server: openresty/1.9.7.1
Date: Mon, 16 Apr 2018 13:11:19 GMT
Content-Type: text/html
Content-Length: 2
Last-Modified: Tue, 12 May 2015 04:01:15 GMT
Connection: keep-alive
ETag: "55517b0b-264"
Content-Range: bytes 0-1/612

测试ok

发送带range的请求到缓存服务

$ curl -r 0-1 -i http://127.0.0.1:10009
HTTP/1.1 206 Partial Content
Server: openresty/1.9.7.1
Date: Mon, 16 Apr 2018 13:12:13 GMT
Content-Type: text/html
Content-Length: 2
Connection: keep-alive
Last-Modified: Tue, 12 May 2015 04:01:15 GMT
ETag: "55517b0b-264"
X-Proxy-Cache: MISS
Content-Range: bytes 0-1/612

返回ok,可以看到 X-Proxy-Cache 是miss的,此时,文件应该缓存到了缓存目录中,下面去看看

查看cache目录

$ sudo tree ngcache
ngcache
└── e
    └── 81
        └── 5ad01815bca14bc0f88a02a882ec881e

sudo cat ngcache/e/81/5ad01815bca14bc0f88a02a882ec881e

看到的结果是 缓存了整个文件

再次使用带有range的请求访问缓存服务,这次的range范围有所改变

$ curl -r 2-10 -i http://127.0.0.1:10009
HTTP/1.1 206 Partial Content
Server: openresty/1.9.7.1
Date: Mon, 16 Apr 2018 13:14:07 GMT
Content-Type: text/html
Content-Length: 9
Connection: keep-alive
Last-Modified: Tue, 12 May 2015 04:01:15 GMT
ETag: "55517b0b-264"
X-Proxy-Cache: HIT
Content-Range: bytes 2-10/612

DOCTYPE h%

可以看到缓存命中了 X-Proxy-Cache 为 hit。

总结

上面的测试和第二个猜想相符合,那为什么会这样呢?在 mailing list中找到了一段讨论

nginx removes Range header (as well as several other headers)
before passing request to upstream to make sure full response will
be cached and other requests for the same uri will be served
correctly.

可以看到 nginx 在往源站发送请求的时候,把range这个header去掉了,所以源站返回给nginx cache的是整个文件,所以缓存的也是整个文件了。

再来看看 ngx_http_proxy_module 的文档

If caching is enabled, the header fields “If-Modified-Since”, “If-Unmodified-Since”, “If-None-Match”, “If-Match”, “Range”, and “If-Range” from the original request are not passed to the proxied server.
You may be able to make it work by adding something like proxy_set_header Range $http_range, but you will also need to add the range to the cache key, so it probably won’t be too effective (btw, also need to handle the cache in which the original request did not specify a range)

改进 一

如果是一个大文件下载,请求的是文件的一部分,下载的却是整个文件,势必会造成流量暴增,下载很慢,如果我们想要 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;   

测试ok

你可能感兴趣的:(nginx)