我希望 Nginx 在升级或重新启动后端服务、执行数据库迁移或执行其他一些管理任务时短时间暂停(保留)http 请求,而不会给最终用户造成错误。
基本上我想执行以下操作顺序:
- 告诉 Nginx 停止将请求转发到我的后端,而是将它们保存在异步队列中;
- 等待所有待处理的后端请求完成并收到通知;
- 升级、重启或以其他方式操作空闲的后端服务;
- 使用私有地址快速验证后端服务是否正常运行;
- 打开 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 线程,其中分享了解决方案。
答案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_