如何在后端升级期间暂停 Nginx 请求

如何在后端升级期间暂停 Nginx 请求

我希望 Nginx 在升级或重新启动后端服务、执行数据库迁移或执行其他一些管理任务时短时间暂停(保留)http 请求,而不会给最终用户造成错误。

基本上我想执行以下操作顺序:

  1. 告诉 Nginx 停止将请求转发到我的后端,而是将它们保存在异步队列中;
  2. 等待所有待处理的后端请求完成并收到通知;
  3. 升级、重启或以其他方式操作空闲的后端服务;
  4. 使用私有地址快速验证后端服务是否正常运行;
  5. 打开 Nginx 的闸门,让所有待处理的请求通过。

理想情况下,这将允许我执行需要独占访问整个后端服务器的管理任务,例如重新启动、升级或迁移,而不会对最终用户造成比延迟更严重的后果,希望延迟时间少于一分钟。

我已经发现此解决方案,但它没有解决第 2 点。此外,它需要将 Lua 解释器编译到 Nginx 中,这可能意味着内存泄漏和安全问题。

是否有任何配置技巧或 Nginx 模块专门针对此问题?可以使用普通 Nginx 来完成吗?也许可以通过测试控制文件是否存在?

其他管理员如何解决这一问题?

(我知道,万能的、有点杂乱的uWSGI 应用服务器具有此功能以及数百个其他功能,但我宁愿避免在 Nginx 和我的后端之间引入另一个元素。)

答案1

在寻找此问题的解决方案时,我偶然发现了一个名为失眠这说明了一种使用 Lua 的简单而优雅的方法。假设您已经安装了 Lua 模块,您首先需要在 顶部启用它nginx.conf

load_module /usr/lib/nginx/modules/ndk_http_module.so;
load_module /usr/lib/nginx/modules/ngx_http_lua_module.so;

然后,在您的http块中,设置一个共享的 Lua 变量来跟踪暂停/恢复状态:

http {
    lua_shared_dict state 12k;
    init_by_lua_block {
        ngx.shared.state:set("suspend", false)
    }
    # rest of your http block
}

接下来,在您的服务器块中,设置一个秘密位置来告诉服务器暂停/恢复:

location = /suspend/MySuperSecretMagicString {
    if ($request_method = PUT) {
        content_by_lua_block {
            ngx.req.read_body()
            content = ngx.req.get_body_data()
            if (content == "go2sleep") then
                ngx.shared.state:set("suspend", true)
            else
                ngx.shared.state:set("suspend", false)
            end
        }
    }
}

然后在主位置块中,再添加一点 Lua:

location / {
    access_by_lua_block {
        while (ngx.shared.state:get("suspend") == true) do
            ngx.sleep(0.2)
        end
    }
    proxy_pass http://my-backend;
}

现在您可以发出进入挂起模式的请求:

curl -X PUT -d go2sleep http://localhost/suspend/MySuperSecretMagicString

要将所有缓冲的请求释放到后端,只需go2sleep用其他任何内容替换即可:

curl -X PUT -d UnleashTheHounds http://localhost/suspend/MySuperSecretMagicString

请注意,每个暂停的请求都有自己的工作程序,因此您需要有足够的工作worker_connections程序来处理预期的积压。请参阅失眠知识库以进一步了解评论和一些附加功能。Basecamp 的中场休息存储库。

再次声明,这项技术不是我发明的。所有荣誉都应归于 GitHub 用户“solso”。

答案2

我猜您正在处理停机时间最短的维护场景。

我建议您使用备份服务器来保留请求所需的秒数<20>(或)甚至<100>,并在应用程序重新启动后重定向到原始 URI。

您可以关注下面的 nginx 线程,其中分享了解决方案。

http://forum.nginx.org/read.php?2,177,177#msg-177

答案3

您可以配置 nginx 来执行一个脚本,以便处理并将 http 调用传递给某些队列进程(如 beanstalkd),通过在 502 BAD GATEWAY 和/或 503 SERVICE UNAVAILABLE 上使用错误处理。(当您的后端服务不可用时出错)。

然后,在后端升级后,从 beanstalkd 弹出请求,并将其处理到您的后端服务。

此外,如果您的后端服务意外出现故障,这可以作为 HA 解决方案以避免丢失 api 调用。设置 jenkins/cron 来自动检查和处理任何 beanstalk 队列。

答案4

在您的server部分

if ( -f /etc/nginx/sites-enabled/maintenance.ngx ) {
    return 503;
}
error_page  503 /maintenance.html

使用

# cd /etc/nginx/sites-enabled && mv maintenance.ngx_ maintenance.ngx

并恢复

# cd /etc/nginx/sites-enabled && mv maintenance.ngx maintenance.ngx_

相关内容