我让 Nginx 位于 前面gunicorn
,而 又位于应用程序前面django
。
核心问题是“为什么我的回复没有被缓存?”然而,我对此还不是很了解,因此以下是我的假设:应该发生(以防我的核心理解有缺陷)。
请求A
命中Nginx
,例如,请求json
来自 REST 服务的一些内容。Nginx 的缓存中没有这些内容,因此它会将其传递给Gunicorn/Django
。生成响应,将其传回 Nginx,然后缓存,最后返回到客户端。
然后!
请求B
请求相同的资源。Nginx 已将其缓存,因此可直接提供服务,而无需访问 django 应用程序。
基于这个假设并经过大量阅读后,我最终在我的 nginx 配置中得到了这个最小的配置sites-enabled
:
proxy_cache_path /tmp/nginx keys_zone=one:20m inactive=60m;
proxy_cache_key "$host$request_uri";
server {
listen 8080;
server_name localhost;
proxy_cache one;
location / {
add_header X-Proxy-Cache $upstream_cache_status;
proxy_ignore_headers X-Accel-Expires Expires Cache-Control;
proxy_pass http://127.0.0.1:8000;
}
}
如果我测试几个请求,我会得到以下响应:
curl -X GET -I http://localhost:8080
HTTP/1.1 200 OK
Server: nginx/1.4.6 (Ubuntu)
Date: Wed, 06 May 2015 01:35:38 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Cookie
X-Frame-Options: SAMEORIGIN
Set-Cookie: csrftoken=b6UG5X4ZlGwVUYfHSIkq4PKBIxicpWxc; expires=Wed, 04-May-2016 01:35:38 GMT; Max-Age=31449600; Path=/
X-Proxy-Cache: MISS
注意:我认为 cookie 没问题,因为我没有将其包含在cache_key
指令中。但我也可能错了。
尽管对同一资源发出了多次请求,但我从未获得缓存命中。此外,proxy_cache_path
目录中没有写入任何缓存文件。
有人能告诉我为什么没有缓存任何响应吗?
谢谢!
答案1
尝试缓存包含Set-Cookie
标头的实体是一个非常糟糕的主意。这是天生禁止由 nginx 执行,除非proxy_ignore_headers
指令中说明。
忽略此标头加上Vary: Cookie
回复中的标头将使您的缓存非常无效,因为单一资源将具有与请求它的访问者数量一样多的缓存条目。
还请注意,Vary
只有从版本开始,缓存算法才会考虑标头1.7.7
。使用以前的 nginx 版本proxy_ignore_headers Set-Cookie;
会导致大量 cookie 重复,因为Set-Cookie
缓存回复中的标头将被发送回所有命中缓存条目的请求。
答案2
在我看来,问题在于上游服务器没有发送包含到期日期(Expires:
)或缓存验证器(例如Last-Modified:
)的响应。(cookie 到期时间与缓存无关。)
这HTTP 1.1 规范说:
如果响应中没有缓存验证器或明确的过期时间,我们不希望它被缓存,但某些缓存可能会违反此期望(例如,当网络连接很少或没有网络连接时)。
(重点已添加。)
因此,您的 Django 设置似乎未启用缓存。我建议您启用每个站点缓存。如果这样做,Django 将在其响应中生成 Nginx 缓存所需的标头。
另一个选项是使用proxy_cache_valid
Nginx 配置中的选项。我使用了与您的设置类似的设置并复制了您的行为,然后我添加了一个选项proxy_cache_valid any 5m;
,告诉 Nginx 将具有任何状态代码 ( ) 的响应缓存any
5 分钟5m
。一旦我这样做了,我就获得了缓存命中。