AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / server / 问题 / 537269
Accepted
Vladimir Panteleev
Vladimir Panteleev
Asked: 2013-09-09 03:59:14 +0800 CST2013-09-09 03:59:14 +0800 CST 2013-09-09 03:59:14 +0800 CST

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

  • 772

我正在尝试将 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;
    }
}

这不起作用 - 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 返回特定的状态代码时)?

nginx
  • 2 2 个回答
  • 61068 Views

2 个回答

  • Voted
  1. Best Answer
    Vladimir Panteleev
    2013-09-09T04:17:42+08:002013-09-09T04:17:42+08:00

    关键点:

    • 不要upstream为故障转移而烦恼,如果 ping 一个服务器会启动另一个服务器 - 没有办法告诉 nginx(至少,不是 FOSS 版本)第一台服务器再次启动。nginx 将在第一个请求时按顺序尝试服务器,但不会尝试后续请求,尽管有任何backup或weight设置fail_timeout。
    • 在使用命名位置实施故障转移时,您必须启用。recursive_error_pageserror_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
        }
    }
    

    原始答案/研究日志如下:


    这是我发现的一个更好的解决方法,这是一个改进,因为它不需要客户端重定向:

    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块中的第一个条目标记为关闭,因此它不会在连续请求时按顺序尝试服务器。我尝试添加weight=1000000000 fail_timeout=1到第一个条目但没有效果。到目前为止,我还没有找到任何不涉及客户端重定向的解决方案。


    编辑:我希望我知道的另一件事 - 要从error_page处理程序获取错误状态,请使用以下语法:error_page 502 = @handle_502;- 等号将导致 nginx 从处理程序获取错误状态。


    编辑:我让它工作了!除了error_page上面的修复,所有需要的是启用recursive_error_pages!

    • 25
  2. ALex_hha
    2013-09-09T04:22:51+08:002013-09-09T04:22:51+08:00

    您可以尝试以下内容

    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;
        }
    
    }
    
    • 3

相关问题

  • Gzip 与反向代理缓存

  • nginx 作为代理的行为

  • Nginx 学习资源 [关闭]

  • 提供 70,000 个静态文件 (jpg) 的最佳方式?

  • 在 Apache、LightTPD 和 Nginx Web 服务器上提供 PHP 5.x 应用程序的现状?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    新安装后 postgres 的默认超级用户用户名/密码是什么?

    • 5 个回答
  • Marko Smith

    SFTP 使用什么端口?

    • 6 个回答
  • Marko Smith

    命令行列出 Windows Active Directory 组中的用户?

    • 9 个回答
  • Marko Smith

    什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同?

    • 3 个回答
  • Marko Smith

    如何确定bash变量是否为空?

    • 15 个回答
  • Martin Hope
    Tom Feiner 如何按大小对 du -h 输出进行排序 2009-02-26 05:42:42 +0800 CST
  • Martin Hope
    Noah Goodrich 什么是 Pem 文件,它与其他 OpenSSL 生成的密钥文件格式有何不同? 2009-05-19 18:24:42 +0800 CST
  • Martin Hope
    Brent 如何确定bash变量是否为空? 2009-05-13 09:54:48 +0800 CST
  • Martin Hope
    cletus 您如何找到在 Windows 中打开文件的进程? 2009-05-01 16:47:16 +0800 CST

热门标签

linux nginx windows networking ubuntu domain-name-system amazon-web-services active-directory apache-2.4 ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve