我试图设置nginx作为一个反向代理,与大量的后端服务器。 我想按需启动后端(在第一个请求中),所以我有一个控制进程(由HTTP请求控制),根据接收到的请求启动后端。
我的问题是configurationnginx来做到这一点。 以下是我到目前为止:
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; } }
这是行不通的 – nginx似乎忽略了从控制服务器返回的任何状态码。 @handle_502
位置中的error_page
指令都不起作用,并且451代码原样发送到客户端。
我放弃了尝试使用内部nginxredirect为此,并试图修改控制服务器发出307redirect到相同的位置(以便客户端将重试相同的请求,但现在与后端服务器启动)。 然而,现在nginx使用从后端请求尝试(502)获得的状态代码愚蠢地覆盖状态代码,尽pipe控制服务器正在发送“位置”标题。 我终于通过将error_page行更改为error_page 502 =307 @handle_502;
来使其“工作” ,从而强制所有的控制服务器回复以307代码发送回客户端。 这是非常冒险和不可取的,因为1)根据控制服务器的响应,不能控制下一步应该做什么(理想情况下,我们只想在控制服务器报告成功时重试后端),2)不是所有的HTTP客户端支持HTTPredirect(例如,curl用户和使用libcurl的应用程序需要明确地启用以下redirect)。
如何让nginx尝试代理上游服务器A,然后是B,然后又是A(理想情况下,只有当B返回特定的状态码)时,正确的方法是什么?
关键点:
upstream
模块进行故障转移 – 没办法告诉nginx(至less不是FOSS版本)第一个服务器重新启动。 nginx会在第一个请求中按顺序尝试服务器,但不pipe后续请求,尽pipe有backup
, weight
或fail_timeout
设置。 error_page
和命名位置实现故障转移时,您必须启用recursive_error_pages
。 proxy_intercept_errors
来处理从上游服务器发送的错误代码。 =
语法(例如error_page 502 = @handle_502;
)需要正确处理指定位置中的错误代码。 如果不使用=
,nginx将使用前一个块的错误代码。 原始答复/研究日志如下:
这是一个更好的解决方法,我发现,这是一个改进,因为它不需要客户端redirect:
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; }
然后,让控制服务器在“成功”返回502,并希望代码永远不会被后端返回。
更新:nginx将upstream
块中的第一个条目标记为closures,所以它不会在连续的请求中尝试服务器。 我已经尝试添加weight=1000000000 fail_timeout=1
到第一个条目没有任何效果。 到目前为止,我还没有find任何不涉及客户端redirect的解决scheme。
编辑:我希望我知道的另一件事 – 从error_page
处理程序获取错误状态,使用此语法: error_page 502 = @handle_502;
– 等号会导致nginx从处理程序中获取错误状态。
编辑:我得到它的工作! 除了上面的error_page
修正之外,所有需要的都是启用recursive_error_pages
!
你可以尝试像下面这样的东西
upstream backend { server a.example.net; server b.example.net backup; } server { listen 80; server_name www.example.net; proxy_next_upstream error timeout http_502; location / { proxy_pass http://backend; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-for $remote_addr; } }