nginx主动关闭keepalive连接的核心是应用层定时检测空闲连接,不依赖TCP保活;源码通过事件循环、连接结构体管理及红黑树定时器(ngx_add_timer)实现超时控制,每次请求重置计时。

nginx 对 keepalive 连接的超时主动关闭,核心在于 空闲连接的定时检测与清理,不依赖 TCP 层的保活(TCP keepalive),而是由 nginx 自己在应用层维护连接状态并触发关闭。源码层面的关键逻辑集中在事件循环、连接结构体管理和定时器调度三部分。
keepalive 连接的生命周期从 accept 后开始管理
当一个 HTTP 连接完成请求处理且满足 keepalive 条件(如 HTTP/1.1、响应头允许、未显式关闭等),nginx 不会立即 close socket,而是将该连接从“活跃请求处理态”转入“空闲 keepalive 态”。此时:
- 连接的
ngx_http_request_t被销毁,但底层ngx_connection_t仍保留,并挂入当前 worker 进程的 keepalive 连接队列(ngx_http_connection_t->free_connections或更准确地说,通过ngx_http_keepalive_pool_t管理) -
c->data指向一个轻量级的ngx_http_keepalive_ctx_t结构,保存解析上下文和超时时间点 - 连接的读事件被重新注册为
ngx_http_keepalive_handler,写事件通常禁用
超时判断基于 ngx_timer_wheel 和红黑树定时器
nginx 使用高效定时器机制管理 keepalive 超时。关键点如下:
- 每个空闲 keepalive 连接调用
ngx_add_timer(c->read, clcf->keepalive_timeout),将读事件加入全局定时器(基于红黑树实现,ngx_event_timer_rbtree) - worker 事件循环(
ngx_process_events_and_timers)每次迭代前检查定时器:若红黑树根节点的超时时间已到,就执行对应事件的 handler —— 即c->read->handler == ngx_http_keepalive_handler -
ngx_http_keepalive_handler被触发时,实际执行的是ngx_http_set_keepalive的清理分支:它会调用ngx_close_connection(c)主动关闭 socket,并释放连接资源
配置项如何影响源码行为
以下配置直接映射到源码中的关键变量和路径:
-
keepalive_timeout 65s;→ 赋值给clcf->keepalive_timeout,作为ngx_add_timer的毫秒参数;若设为 0,则跳过添加定时器,连接在下一次读事件无数据时立即关闭 -
keepalive_requests 100;→ 记录在ngx_http_connection_t->requests,每次复用时递增;达到阈值后,在ngx_http_finalize_request中强制设置r->keepalive = 0,跳过进入 keepalive 队列 -
tcp_nodelay on;与 keepalive 无关,但影响首次响应延迟;而tcp_keepalive(需 1.19.1+)控制内核 TCP 层保活参数,是独立开关
调试与验证建议
想确认 keepalive 关闭是否按预期发生,可结合源码与运行时观察:
- 加日志:在
src/http/ngx_http_request.c的ngx_http_set_keepalive开头和ngx_http_keepalive_handler中插入ngx_log_debug,输出连接地址与超时剩余时间 - 抓包验证:用
tcpdump抓 nginx 侧 socket,观察 FIN 包是否在空闲约keepalive_timeout后发出,而非由客户端发起 - 查看连接状态:使用
ss -tnp | grep :80,处于ESTAB但无数据收发的连接,即为 keepalive 空闲连接;超时后应消失
不复杂但容易忽略:nginx 的 keepalive 超时是单次计时,每次新请求都会重置定时器;它不是“总存活时间”,而是“最后一次数据收发后的静默等待上限”。

















