Nginx 在上游启动时绕过缓存,在关闭时使用缓存
Nginx bypass cache if upstream is up and use cache if down
要在上游启动时绕过缓存(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
How to configure NginX to serve Cached Content only when Backend is down (5xx Resp. Codes)?
https://serverfault.com/questions/752838/nginx-use-proxy-cache-if-backend-is-down
它并没有像我预期的那样工作。感谢任何帮助。
这与链接到的其他类似问题一样,都是 XY Problem 的示例。
用户想做 X,错误地认为解决方案是 Y 但不能做 Y,因此寻求有关如何做 Y 的帮助,而不是实际询问 X。这总是会给那些试图给出解决方案的人带来问题回答。
在这种情况下,实际问题 X 似乎是您希望对后端进行故障转移,但希望避免在单独的服务器实例上花钱,并且想知道有哪些选项可用.
为此使用缓存的想法并未完全取消,但您必须像故障转移服务器一样处理和设置缓存,这意味着它必须是一个与后端完全独立的系统。这排除了与后端密切相关的proxy_cache
。
站在你的立场上,我将设置一个 memcached 服务器并将其配置为缓存你的东西,但通常不会为你的请求提供服务,除非出现 50x 错误。
Nginx 有一个memcached module 可以编译和使用,但它没有向memcached 添加项目的工具。您必须在 Nginx 之外执行此操作(通常在您的后端应用程序中)。
设置 memcached 的指南 can be found here 或者只是进行网络搜索。一旦启动并且 运行,这将在 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;
}
}
OpenResty 的 3rd party memc module 比有限的标准 memcached 模块好得多,它允许您直接在 Nginx 中添加内容。
OpenResty 也有非常灵活的 lua-resty-memcached 这实际上是最好的选择。
对于这两种情况,您都需要将它们编译到您的 Nginx 中并熟悉如何设置它们。如果您需要这方面的帮助,请在此处使用 OpenResty 标签提出新问题或尝试使用 OpenResty 支持系统。
总结
- 您真正需要的是故障转移服务器。
- 这必须独立于后端。
- 您可以像这样使用缓存系统,但如果您不能忍受在最短 1 秒的时间内获取缓存结果,就不能
proxy_cache
。
- 您需要扩展典型的 Nginx 安装才能执行此操作。
让我们讨论一下使用两台服务器的非常简单的设置。一个 运行 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
指定的时间已经过去。所以在这里你必须决定在哪些情况下你仍然想从缓存中提供服务。
The directive's parameters are the same as for proxy_next_upstream
.
您将需要这些:
error
:如果服务器仍在运行,但没有响应,或者没有正确响应。
timeout
: 连接服务器、请求或响应超时。这也是为什么要将 proxy_connect_timeout
设置为较低值的原因。默认值为 60 秒,对于最终用户来说太长了。
updating
:已经有新内容请求正在处理中。 (不是真的需要,但从性能的角度来看更好。)
http_xxx
参数对您没有多大作用,当后端服务器关闭时,您将永远不会收到任何这些代码的响应。
然而,在我的真实案例中,后端服务器也是 nginx,它代理到本地主机上的不同端口。因此,当 nginx 运行 正常,但任何这些后端出现故障时,参数 http_502
、http_503
和 http_504
将不再有用,因为这些正是我将要使用的 http 代码收到。
http_403
、http_404
和 http_500
我不想从缓存中提供服务。当文件被禁止 (403) 或不再位于后端 (404) 或脚本出错 (500) 时,这是有原因的。但这是我的看法。
它不起作用,因为 http_500、http_502、http_503、http_504 代码需要来自后端。在你的情况下 504 是 nginx 代码。
所以你需要具备以下条件:
proxy_connect_timeout 10s;
proxy_cache_use_stale ... timeout ...
或
proxy_cache_use_stale ... updating ...
或两者。
要在上游启动时绕过缓存(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
How to configure NginX to serve Cached Content only when Backend is down (5xx Resp. Codes)?
https://serverfault.com/questions/752838/nginx-use-proxy-cache-if-backend-is-down
它并没有像我预期的那样工作。感谢任何帮助。
这与链接到的其他类似问题一样,都是 XY Problem 的示例。
用户想做 X,错误地认为解决方案是 Y 但不能做 Y,因此寻求有关如何做 Y 的帮助,而不是实际询问 X。这总是会给那些试图给出解决方案的人带来问题回答。
在这种情况下,实际问题 X 似乎是您希望对后端进行故障转移,但希望避免在单独的服务器实例上花钱,并且想知道有哪些选项可用.
为此使用缓存的想法并未完全取消,但您必须像故障转移服务器一样处理和设置缓存,这意味着它必须是一个与后端完全独立的系统。这排除了与后端密切相关的proxy_cache
。
站在你的立场上,我将设置一个 memcached 服务器并将其配置为缓存你的东西,但通常不会为你的请求提供服务,除非出现 50x 错误。
Nginx 有一个memcached module 可以编译和使用,但它没有向memcached 添加项目的工具。您必须在 Nginx 之外执行此操作(通常在您的后端应用程序中)。
设置 memcached 的指南 can be found here 或者只是进行网络搜索。一旦启动并且 运行,这将在 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;
}
}
OpenResty 的 3rd party memc module 比有限的标准 memcached 模块好得多,它允许您直接在 Nginx 中添加内容。
OpenResty 也有非常灵活的 lua-resty-memcached 这实际上是最好的选择。
对于这两种情况,您都需要将它们编译到您的 Nginx 中并熟悉如何设置它们。如果您需要这方面的帮助,请在此处使用 OpenResty 标签提出新问题或尝试使用 OpenResty 支持系统。
总结
- 您真正需要的是故障转移服务器。
- 这必须独立于后端。
- 您可以像这样使用缓存系统,但如果您不能忍受在最短 1 秒的时间内获取缓存结果,就不能
proxy_cache
。 - 您需要扩展典型的 Nginx 安装才能执行此操作。
让我们讨论一下使用两台服务器的非常简单的设置。一个 运行 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
指定的时间已经过去。所以在这里你必须决定在哪些情况下你仍然想从缓存中提供服务。
The directive's parameters are the same as for proxy_next_upstream
.
您将需要这些:
error
:如果服务器仍在运行,但没有响应,或者没有正确响应。
timeout
: 连接服务器、请求或响应超时。这也是为什么要将 proxy_connect_timeout
设置为较低值的原因。默认值为 60 秒,对于最终用户来说太长了。
updating
:已经有新内容请求正在处理中。 (不是真的需要,但从性能的角度来看更好。)
http_xxx
参数对您没有多大作用,当后端服务器关闭时,您将永远不会收到任何这些代码的响应。
然而,在我的真实案例中,后端服务器也是 nginx,它代理到本地主机上的不同端口。因此,当 nginx 运行 正常,但任何这些后端出现故障时,参数 http_502
、http_503
和 http_504
将不再有用,因为这些正是我将要使用的 http 代码收到。
http_403
、http_404
和 http_500
我不想从缓存中提供服务。当文件被禁止 (403) 或不再位于后端 (404) 或脚本出错 (500) 时,这是有原因的。但这是我的看法。
它不起作用,因为 http_500、http_502、http_503、http_504 代码需要来自后端。在你的情况下 504 是 nginx 代码。 所以你需要具备以下条件:
proxy_connect_timeout 10s;
proxy_cache_use_stale ... timeout ...
或
proxy_cache_use_stale ... updating ...
或两者。