我正在尝试将 nginx 设置为具有大量后端服务器的反向代理。我想按需启动后端(在第一个请求时),所以我有一个控制过程(由 HTTP 请求控制),它根据它收到的请求启动后端。
我的问题是配置 nginx 来做到这一点。这是我到目前为止所拥有的:
server {
listen 80;
server_name $DOMAINS;
location / {
# redirect to named location
#error_page 418 = @backend;
#return 418; # doesn't work - error_page doesn't work after redirect
try_files /nonexisting-file @backend;
}
location @backend {
proxy_pass http://$BACKEND-IP;
error_page 502 @handle_502; # Backend server down? Try to start it
}
location @handle_502 { # What to do when the backend server is not up
# Ping our control server to start the backend
proxy_pass http://127.0.0.1:82;
# Look at the status codes returned from control server
proxy_intercept_errors on;
# Fallback to error page if control server is down
error_page 502 /fatal_error.html;
# Fallback to error page if control server ran into an error
error_page 503 /fatal_error.html;
# Control server started backend successfully, retry the backend
# Let's use HTTP 451 to communicate a successful backend startup
error_page 451 @backend;
}
location = /fatal_error.html {
# Error page shown when control server is down too
root /home/nginx/www;
internal;
}
}
Run Code Online (Sandbox Code Playgroud)
这不起作用 - nginx 似乎忽略了从控制服务器返回的任何状态代码。位置中的error_page
指令都@handle_502
不起作用,451 代码按原样发送给客户端。
我放弃了为此使用内部 nginx 重定向的尝试,并尝试修改控制服务器以将 307 重定向发送到同一位置(以便客户端重试相同的请求,但现在后端服务器已启动)。然而,现在 nginx 愚蠢地用它从后端请求尝试(502)中获得的状态代码覆盖状态代码,尽管控制服务器正在发送“位置”标头。我终于通过将 error_page 行更改为“工作”error_page 502 =307 @handle_502;
,从而强制将所有控制服务器回复发送回带有 307 代码的客户端。这是非常hacky和不可取的,因为1)根据控制服务器的响应,无法控制nginx接下来应该做什么(理想情况下,我们只想在控制服务器报告成功时重试后端),以及2)并非所有的HTTP客户端支持 HTTP 重定向(例如 curl 用户和使用 libcurl 的应用程序需要显式启用以下重定向)。
让 nginx 尝试代理到上游服务器 A,然后是 B,然后又是 A(理想情况下,仅当 B 返回特定状态代码时)的正确方法是什么?
Vla*_*eev 22
关键点:
upstream
为故障转移而烦恼,如果 ping 一个服务器会启动另一个服务器 - 没有办法告诉 nginx(至少,不是 FOSS 版本)第一台服务器再次启动。nginx 将在第一个请求时按顺序尝试服务器,但不会尝试后续请求,不管有任何backup
,weight
或fail_timeout
设置。recursive_error_pages
在使用error_page
和命名位置实施故障转移时启用。proxy_intercept_errors
以处理从上游服务器发送的错误代码。=
语法(例如error_page 502 = @handle_502;
)需要正确地处理在指定的位置的错误代码。如果=
未使用,nginx 将使用上一个块中的错误代码。这是一个总结:
server {
listen ...;
server_name $DOMAINS;
recursive_error_pages on;
# First, try "Upstream A"
location / {
error_page 418 = @backend;
return 418;
}
# Define "Upstream A"
location @backend {
proxy_pass http://$IP:81;
proxy_set_header X-Real-IP $remote_addr;
# Add your proxy_* options here
}
# On error, go to "Upstream B"
error_page 502 @handle_502;
# Fallback static error page, in case "Upstream B" fails
root /home/nginx/www;
location = /_static_error.html {
internal;
}
# Define "Upstream B"
location @handle_502 { # What to do when the backend server is not up
proxy_pass ...;
# Add your proxy_* options here
proxy_intercept_errors on; # Look at the error codes returned from "Upstream B"
error_page 502 /_static_error.html; # Fallback to error page if "Upstream B" is down
error_page 451 = @backend; # Try "Upstream A" again
}
}
Run Code Online (Sandbox Code Playgroud)
原始答案/研究日志如下:
这是我发现的一个更好的解决方法,这是一个改进,因为它不需要客户端重定向:
upstream aba {
server $BACKEND-IP;
server 127.0.0.1:82 backup;
server $BACKEND-IP backup;
}
...
location / {
proxy_pass http://aba;
proxy_next_upstream error http_502;
}
Run Code Online (Sandbox Code Playgroud)
然后,只需让控制服务器在“成功”时返回 502,并希望后端永远不会返回代码。
更新:nginx 一直将upstream
块中的第一个条目标记为关闭,因此它不会在连续请求中按顺序尝试服务器。我试过添加weight=1000000000 fail_timeout=1
到第一个条目没有效果。到目前为止,我还没有找到任何不涉及客户端重定向的解决方案。
编辑:我希望我知道的另一件事 - 要从error_page
处理程序获取错误状态,请使用以下语法:error_page 502 = @handle_502;
- 等号将导致 nginx 从处理程序获取错误状态。
编辑:我让它工作了!除了error_page
上面的修复之外,所需要的只是启用recursive_error_pages
!
归档时间: |
|
查看次数: |
56619 次 |
最近记录: |