Nginx Keepalive空闲链表是每个监听端口独立维护的ls->keepalive链表,用于暂存满足条件的已处理连接;连接在响应结束后被置idle=1、插入该链表头部,新请求时优先复用未超时连接,超时或超限则由定时器清理。

理解 Nginx 中 Keepalive 连接的空闲链表管理,关键在于看清它如何复用 TCP 连接、避免频繁创建销毁,以及怎样高效地维护“可用但暂时没请求”的连接。核心逻辑不在 HTTP 层,而在 ngx_event_connect.c 和 ngx_http_request.c 的协作中,尤其依赖 ngx_connection_t 的状态字段与两个全局链表:空闲连接池(ngx_cycle->connections 中已建立但空闲的)和 Keepalive 连接队列(ngx_http_keepalive_pool 或更准确地说,每个 listening socket 对应的 listen->connection 下挂载的 keepalive 链表)。
Keepalive 连接如何进入空闲链表
当一个 HTTP 请求处理完成、响应发送完毕,且满足 Keepalive 条件(如客户端发了 Connection: keep-alive、未超 keepalive_timeout、未达 keepalive_requests 上限),Nginx 不会直接关闭连接,而是:
- 将连接从当前请求的读/写事件中移除(调用
ngx_del_timer清除超时定时器); - 把连接的
read->handler改为ngx_http_keepalive_handler,write->handler设为空; - 把连接插入到监听套接字(
ls->listening)的ls->keepalive链表头部(LIFO); - 重置连接状态:
c->data = NULL,c->requests++,并设置c->idle = 1标记为空闲态。
这个 ls->keepalive 就是真正意义上的“Keepalive 空闲连接链表”,由监听端口维度隔离,避免跨端口误复用。
空闲连接如何被复用或清理
新请求到来时,Nginx 在 ngx_http_init_connection 中尝试从对应监听端口的 keepalive 链表里取连接:
- 遍历
ls->keepalive,找到第一个未超时(ngx_current_msec - c->idle_time )、且未超请求数限制的连接; - 将其从链表中摘下(
ngx_queue_remove),重置c->idle = 0,恢复读事件监听; - 复用该连接继续处理新请求,无需三次握手和 TLS 握手(若启用了 SSL session reuse)。
同时,后台有定时器(ngx_event_expire_timers)周期性扫描所有空闲连接,对超时或超请求数的连接执行 ngx_http_close_idle_connection —— 关闭 socket、回收内存、归还到连接池(cycle->free_connections)。
关键数据结构与字段含义
几个易混淆但必须厘清的字段:
-
c->idle:仅表示“当前是否处于 Keepalive 空闲状态”,不是全局空闲标志; -
c->idle_time:进入空闲态时记录的毫秒时间戳,用于计算空闲时长; -
ls->keepalive:ngx_queue_t类型,挂的是ngx_connection_t的queue字段,非独立结构体; -
cycle->free_connections:连接池,存放所有可分配的新连接(包括刚关闭的复用连接),与 Keepalive 空闲链表无关; -
c->requests:该连接已处理的请求数,用于判断是否达到keepalive_requests上限。
注意:ngx_connection_t 没有“空闲链表指针”字段,空闲管理完全靠外部链表 + 状态标记驱动。
调试与验证建议
想通过源码确认行为,可重点关注以下位置:
- 空闲插入点:
ngx_http_set_keepalive(在ngx_http_finalize_connection调用); - 复用获取点:
ngx_http_init_connection中对ls->keepalive的遍历逻辑; - 超时清理点:
ngx_http_close_idle_connection及其调用者ngx_event_expire_timers; - 加日志时,可在
ngx_http_set_keepalive和ngx_http_init_connection中打印c->fd、c->requests、c->idle_time,观察链表变化。
不复杂但容易忽略:Keepalive 空闲链表是 per-listen 的,不同端口(如 80 和 443)互不干扰;且它只管理“已建立、已处理过请求、当前无活跃读写”的连接,不包含刚 accept 进来还没处理请求的新连接。

















