nginx反向代理 – 尝试上游A,然后B,然后A再次

我试图设置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返回特定的状态码)时,正确的方法是什么?

    关键点:

    • 如果ping一个服务器会带来另外一个服务器,那么不要去麻烦upstream模块进行故障转移 – 没办法告诉nginx(至less不是FOSS版本)第一个服务器重新启动。 nginx会在第一个请求中按顺序尝试服务器,但不pipe后续请求,尽pipe有backupweightfail_timeout设置。
    • 在使用error_page和命名位置实现故障转移时,您必须启用recursive_error_pages
    • 启用proxy_intercept_errors来处理从上游服务器发送的错误代码。
    • The =语法(例如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; } }