我将描述使Nginx永久(或至少一年)缓存图像所需要做的一切。

在开始之前,您应该了解一件事:我在此处指出的所有内容均已记录在Nginx的官方缓存指南中,但是我很懒,没有读过它,我希望我能为您节省一些你宝贵的时间

如果您已经在生产中运行Nginx并拥有一定流量,您可能会根据处理请求所需的时间来猜测响应是来自上游服务器而不是来自Nginx缓存的,如果它很慢,那么我们知道作为一个MISS; 另一方面,如果Nginx在缓存中找到响应并进行响应,则为HIT

为了避免任何猜测,最好让Nginx告诉您何时命中或未命中缓存请求,我们通过为HTTP标头提供缓存状态的状态来做到这一点。您可以选择任何想要的名称,X-Cache-Status就像官方指南建议的那样,我喜欢:

location / {
  # . . . 
  add_header X-Cache-Status $upstream_cache_status;
  # . . .
}

现在,我们可以向服务器发出请求,并查看每个特定请求的缓存实际发生了什么:

$ curl -v localhost:8080
. . . 
>
< HTTP/1.1 200 OK
< Server: nginx/1.15.7
< Date: Fri, 20 Dec 2018 00:46:43 GMT
< Content-Type: image/png
< Transfer-Encoding: chunked
< Connection: keep-alive
< Cache-Control: public, max-age=31536000
< X-Cache-Status: HIT

继续阅读指南的第一个片段:

proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m max_size=10g 
                 inactive=60m use_temp_path=off;

server {
    # ...
    location / {
        proxy_cache my_cache;
        proxy_pass http://my_upstream;
    }
}

根据您的设置,此配置可能会或可能不会起作用,请考虑以下几点:

标头中的Cookie

如果NginxSet-Cookie在上游响应中看到标头,则不会缓存

我没有这个问题,但是如果您要确保MISS它不是关于cookie的,则可以简单地忽略所有cookie:

location / {
  # . . . 
  proxy_ignore_headers "Set-Cookie";
  # . . . 
}

缓存控制标头

如果Nginx看到Cache-Control带有PrivateNo-Cache或的标题No-Store则不会缓存

我也没有这个问题,但是如果您要确保它与上游响应中的Cache-Control泄漏无关,还可以通过来忽略此标头proxy_ignore_headers,例如,官方指南中的以下配置将忽略来自上游并强制将任何状态码(不只是200 OK)进行高速缓存30分钟(继续读取):

  location / {
    proxy_ignore_headers Cache-Control;
    proxy_cache_valid any 30m;
  }

这听起来似乎不是一个好主意,相反,您可能希望只缓存这样的响应200 OK

  location / {
    proxy_ignore_headers Cache-Control;
    proxy_cache_valid 200 30m;
  }

如果您愿意,也可以忽略Expires标头:

   proxy_ignore_headers Cache-Control Expires;

代理缓冲

如果Nginx有proxy_buffering: off它将不会缓存

这是on在默认情况下,所以我不知道为什么它会是off,但以防万一:

proxy_buffering on;

这很好地解释了为什么应该这样做on以及为什么会影响缓存。

调整Nginx以缓存更长的时间

此时,此Nginx配置将资源缓存了30分钟,但是我们如何使它缓存更长的时间呢?

我的第一步是改成proxy_cache_valid any 30m;1y

  proxy_cache_valid any 1y;

好的,重新加载Nginx后,我在30分钟后发出了一个新请求:

$ curl -v localhost:8080
. . . 
>
< HTTP/1.1 200 OK
< Server: nginx/1.15.7
< Content-Type: image/png
< Transfer-Encoding: chunked
< Connection: keep-alive
< Cache-Control: public, max-age=31536000
< X-Cache-Status: HIT

所以X-Cache-Status: HIT,那很好。

1小时后怎么样?

$ curl -v localhost:8080
. . . 
>
< HTTP/1.1 200 OK
< Server: nginx/1.15.7
< Content-Type: image/png
< Transfer-Encoding: chunked
< Connection: keep-alive
< Cache-Control: public, max-age=31536000
< X-Cache-Status: MISS

我们得到的X-Cache-Status: MISS显然不是我们想要的,它应该是一个HIT

结果proxy_cache_valid指示Nginx,如果资源没有首先变为非活动状态,则可以缓存1y 该资源。当您请求具有更长到期时间但由于缺少请求而变得不活动的资源时,它将导致高速缓存未命中。

proxy_cache_pathhttp级别指定多久的项目可以保留在缓存中没有被访问过,所以为了缓存资源为1年的配置应该是:

proxy_cache_path . . .  
                 inactive=1y
                 . . . ;

server {
    location / {
        # . . .
        proxy_cache_valid 200 1y;
        # . . . 
    }
}

结论

proxy_cache_path应该inactive比请求的到期时间(proxy_cache_valid)更长的时间。

via https://bithavoc.io/blog/2018/12/20/caching-upstream-forever-with-nginx/

最后更新于 2022年6月26日

使用Nginx永久缓存上游Web资产(proxy cache)
标签: