在对nginx 进行性能测试,发现nginx reload 会导致 http keepalive 模式连接断开(http 1.0或者 http 1.1 connection:close 不存在这种情况),请问这个有什么好的办法处理?
[alibaba/tengine]nginx reload导致 http keepalive 模式连接断开
回答
在对nginx 进行性能测试,发现nginx reload 会导致 http keepalive 模式连接断开(http 1.0或者 http 1.1 connection:close 不存在这种情况
这个是nginx的默认行为。 因为shuttingdown的worker需要尽快退出,而如果允许持续长连接服务请求会导致nginx长时间退出不了。注意正在服务的请求不会断开,但是请求处理完连接不会再被复用(keepalive),直接关闭了。
请问这个有什么好的办法处理?
需要改到nginx core,目前配置指令上没有方法可以支持
- 前端keepalive处理
- 后端keepalive处理
如果直接把 ngx_terminate和ngx_exiting 场景设置连接保活,并且后端invalid 也去掉,这个有没有其他影响?比如这部分连接得不到释放什么的
应该只会导致连接一直复用下去,在连接被客户端/后端主动断开前 无法让nginx worker退出
一般keepalive 都会有timeout和 max keepalive requests ,对于http的keepalive 客户端应该保留的时间不会太长,我不知道阿里这边是怎么处理这个问题的,不知道ngx_terminate和ngx_exiting去掉后,会不会有其他异常的情况出现。。
一般我们用这个功能:http://tengine.taobao.org/document/core.html, 指定shuttingdown的进程再reload之后 指定时间 后退出(如果此时还有请求在处理,则被强制断开,会导致正在处理中的请求失败,但是一般非常少)
Syntax: force_exit exit_time;
Default: —
Context: main
force worker processes to exit after exit_time.
The force_exit support is not enabled by default. You should compile it explicitly:
force_exit 应该不能保证http 1.1 keepalive 不中断吧,force_exit应该是让websocket这种长连接在设定的时间里面强制关闭
force_exit可以保证,强制退出进程。
翻了下force_exit 代码,发现force_exit 只是为了在指定时间内强制退出进程,看样子跟http 1.1 keepalive reload 没太大关系吧?force_exit 只是在原来代码里面加了 ctx->tm <= 0 的时候进程退出,这个不能避免,如果把 ngx_event_timer_rbtree.root == ngx_event_timer_rbtree.sentinel || ctx->tm <= 0 改成 ngx_event_timer_rbtree.root == ngx_event_timer_rbtree.sentinel && ctx->tm <= 0 或许还有点效果吧?
ngx_force_exit_timer_handler(ngx_event_t *ev)
{
ngx_force_exit_timer_ctx *ctx;
if (ev && ev->data) {
ctx = (ngx_force_exit_timer_ctx *) ev->data;
ctx->tm -= 1000;
if (ngx_event_timer_rbtree.root == ngx_event_timer_rbtree.sentinel
|| ctx->tm <= 0)
{
ngx_worker_process_exit(ctx->cycle);
return;
}
ngx_add_timer(ev, 1000);
}
}
发现force_exit 只是为了在指定时间内强制退出进程,看样子跟http 1.1 keepalive reload 没太大关系吧?
正在处理的请求会被强制退出掉(因为 到期退出进程,是直接exit(0)
的)
那等于 force_exit其实也不能解决 nginx reload 会导致 http 1.1 keepalive 连接断开问题
可以用 msgsnd 将连接描述符发到其他 worker 的,与 @chobits 说的相同,如果要改就改到 nginx 核心了,每个 NGINX 版本维护会比较费劲。
可以用 msgsnd 将连接描述符发到其他 worker 的,与 @chobits 说的相同,如果要改就改到 nginx 核心了,每个 NGINX 版本维护会比较费劲。
赞同,不过msgsnd只能迁移fd(描述符),但是整个请求的其他状态(各种request数据结构)在nginx进程里几乎很难迁移。