Nginx如果源站可用时绕过缓存,不可用则使用缓存。

7
为了在上游服务器正常(max-age 1)时绕过缓存,并在其宕机时使用缓存(proxy_cache_use_stale),我创建了以下配置:
proxy_cache_path   /app/cache/ui levels=1:2 keys_zone=ui:10m max_size=1g inactive=30d;
server {
    ...
    location /app/ui/config.json {
        proxy_cache ui;
        proxy_cache_valid 1d;
        proxy_ignore_headers Expires;           
        proxy_hide_header Expires;
        proxy_hide_header Cache-Control;
        add_header Cache-Control "max-age=1, public";
        proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504;
        add_header X-Cache-Status $upstream_cache_status;
        add_header X-Cache-Date $upstream_http_date;
        proxy_pass http://app/config.json;
    }
}

但是当上游服务器关闭时,缓存将不起作用,客户端只会得到504网关超时错误。我已经阅读了以下文章:https://nginx.org/ru/docs/http/ngx_http_proxy_module.html#proxy_cache_use_stale如何配置NginX仅在后端关闭(5xx Resp. Codes)时提供缓存内容?https://serverfault.com/questions/752838/nginx-use-proxy-cache-if-backend-is-down。但这并没有达到我预期的效果。非常感谢您的帮助。
3个回答

12

让我们讨论一个非常简单的设置,有两台服务器。其中一台运行apache2,提供一个简单的HTML页面。另一台运行nginx,反向代理到第一台服务器。

http {
[...]

  proxy_cache_path /var/lib/nginx/tmp/proxy levels=2:2 keys_zone=one:10m inactive=48h max_size=16g use_temp_path=off;

  upstream backend {
    server foo.com;
  }

  server {
  [...]
    location / {
      proxy_cache           one;
      proxy_cache_valid     200 1s;
      proxy_cache_lock      on;

      proxy_connect_timeout 1s;
      proxy_cache_use_stale error timeout updating http_502 http_503 http_504;

      proxy_pass http://backend/
    }
  }
}

这个设置对我很有效。最重要的区别在于proxy_cache_valid 200 1s;。它意味着只有 http 状态码为 200 的响应将被缓存,并且仅在 1 秒内有效。这意味着第一次请求某个资源将从后端获取并放入缓存中。任何进一步请求相同资源将在整整一秒钟内从缓存中提供服务。之后,第一次请求会再次到后端,以此类推。

proxy_cache_use_stale是您情况下的重要部分。它基本上说明了在哪些情况下应该仍然提供缓存版本,尽管已经过了由proxy_cache_valid指定的时间。因此,在这里,您必须决定在哪些情况下仍然希望从缓存中提供服务。

指令的参数与proxy_next_upstream相同。

您需要这些:

error:如果服务器仍然开启,但没有响应或响应不正确。

timeout:连接到服务器,请求或响应超时。这也是为什么您想将proxy_connect_timeout设置为较低值的原因。默认值是60秒,对于终端用户来说太长了。

updating:已经有一个请求正在前往新内容。(不是必需的,但从性能角度来看更好。)

http_xxx参数在后端服务器关闭时对您没有帮助,因为您永远不会收到任何这些代码的响应。

然而,在我的实际案例中,后端服务器也是 Nginx,它代理本地主机上的不同端口。因此,当 Nginx 运行良好,但其中任何一个后端关闭时,参数http_502http_503http_504非常有用,因为这些正是我将收到的 http 状态码。

当文件被禁止(403),不再在后端(404)或脚本出错(500)时,我不想从缓存中提供http_403http_404http_500。但这是我的看法。


proxy_connect_timeoutproxy_cache_use_stale timeout 对我很有帮助,现在我终于得到了最初想要的结果。非常感谢! - Anatoli

2
这段文字的意思是:这个问题和其他类似的问题一样,都是XY问题的例子。
用户想要做X,错误地认为解决方案是Y,但不能做Y,因此请求帮助如何做Y,而不是实际询问X。这通常会给试图提供答案的人造成问题。
在这种情况下,实际问题X似乎是您想要为后端设置故障转移,但不想花费额外的服务器实例,并想知道有哪些选项可用。
使用缓存的想法并非完全错误,但您必须像故障转移服务器一样处理和设置缓存,这意味着它必须是与后端完全独立的系统。这排除了与后端紧密相关的proxy_cache
如果我是您,我会设置一个memcached服务器,并将其配置为缓存您的内容,但通常不提供请求,除非出现50x错误。
这段文字的意思是:Nginx自带一个memcached模块,可以进行编译和使用,但它没有添加项目到memcached的功能。你需要在Nginx之外完成这个操作(通常在后端应用程序中完成)。可以在这里找到设置memcached的指南,或者进行网络搜索。一旦设置好并运行起来,这将在Nginx方面为您工作。
server {
    location / {
        # You will need to add items to memcached yourself here
        proxy_pass             http://backend;
        proxy_intercept_errors on
        error_page             502 504 = @failover;
    }

    location @failover {
        # Assumes memcached is running on Port 11211
        set            $memcached_key "$uri?$args";
        memcached_pass host:11211;
    }
}      

比起有限的标准memcached模块,OpenResty的第三方memc模块(链接)更好,它允许你直接在Nginx中添加内容。
OpenResty还有非常灵活的lua-resty-memcached,实际上这是最好的选择。
对于这两种情况,您需要将它们编译到您的Nginx中,并熟悉如何设置它们。如果您需要帮助,请在此处提出一个带有OpenResty标签的新问题,或尝试OpenResty支持系统。
总结:
1. 实际上您需要的是故障转移服务器。
2. 这必须与后端分开且独立。
3. 您可以使用缓存系统作为此项服务,但如果您不能接受获取缓存结果的最短时间为1秒,则不能使用代理缓存。
4. 您将需要扩展典型的Nginx安装来完成此操作。

谢谢您的回答,但我还有一个问题:初始配置有什么问题,为什么它不起作用? - Anatoli

0

它无法工作是因为后端期望返回 http_500、http_502、http_503、http_504 状态码。在您的情况下,504 是 nginx 的状态码。 因此,您需要具备以下内容:

proxy_connect_timeout 10s;
proxy_cache_use_stale ... timeout ...

或者

proxy_cache_use_stale ... updating ...

或者两者都可以。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接