nginx reload时对http keepalive连接的处理

nginx各协议的reload行为

协议 行为
 http keepalive  server fin
 http2  server fin
 tcp 保持shutdown不断
udp 保持shutdown不断
grpc

基于HTTP2与其保持一致,但是没实测

 

现象

nginx 在reload时,会对http keepalive的连接进行close操作。

抓包可以看见client收到了一个fin报文。

 nginx 的worker也不会长时间留着shutdown状态,而是立刻退出。

 

4层的tcp监听上的连接,会使worker一直保留在shutdown状态。直到连接断开后,进程退出。

代码分析

见函数:ngx_worker_process_cycle,

所有idle的连接,会调用一次read的handler,然后将连接标记为close,最后在处理流程里根据这个标记,调用ngx_http_close_connection。关闭连接。

 

http keepalive过程

keepalive的连接会在每个request处理完的时候ngx_http_finalize_request调用连接关闭ngx_http_finalize_connection

在这个函数里,如果连接设了keepalive,就会进入 ngx_http_set_keepalive 函数

 

上述调用ngx_http_set_keepalive 函数的过程干三个事:

1 rev->handler = ngx_http_keepalive_handler;

c->idle = 1;

3 在2936行直接返回,跳过后面的connection close操作,所以连接还开着。

 

当 nginx reload的时候,2930或2931导致  ngx_http_set_keepalive 不会被调用,所以连接被关闭了,

抓包就看见了一个nginx到client的fin报文。

 

ngx_http_keepalive_handler

idle=1代表进程现在处于等待数据包读入状态。

ngx_http_keepalive_handler函数是数据包后的第一个handler,它的主要功能类似于 ngx_http_wait_request_handler 函数,

0 如果close=1,直接关闭连接。

1 设置idle = 0 (重新变成idle)

2 设置新的handler  = ngx_http_process_request_line

 

request处理完成后,流程会重新走进ngx_http_finalize_request,最终判断是否进入ngx_http_set_keepalive 

A 如果设置了ngx_exiting或者keepalive设置为0,将不会进入ngx_http_set_keepalive,直接将连接关闭。

B 否则再次进入ngx_http_set_keepalive 重新将idle设置为1,等待下一个请求的到来。

 

最后在函数ngx_worker_process_cycle,里。所有连接都关闭了,于是进程退出。

 

另外有个配置叫 worker_shutdown_timeout

https://nginx.org/en/docs/ngx_core_module.html#worker_shutdown_timeout

就是到时间之后,不管什么连接(包括tcp)全部断开进程退出,实现如下:将所有连接全部标记为close,然后再handler流程里close。

 

connection close的时候,会删掉read write timer,所有(三)里边的exit逻辑分支,再所有连接都断开了以后,就使进程退出了。

 

https://hg.nginx.org/nginx/rev/96ae8e57b3dd

 

这个是官方nginx的改动。主要是在nginx退出的时候,给keepalive的client回response时,带一个Connection:close。

基于(二)的代码分析,reload或exit发生时:

当connection处于idle时,nginx会直接将socket close掉。

         然后client再发下一个response过来时,nginx的os回一个reset,client才知道失败了。(A)

当connection处于非idle(request处理过程中),且response还没发回时,会把response的Connection:keepalive改成Connection:close,紧接着socket close。

         client的http层就会知道连接需要断开了。(B)

然后,进程退出。

另外,这个回复close的行为也就是情况(B),与 “keepalive_timeout到期,keepalive_requests满” 时的行为保持一致。

 

参考

https://github.com/alibaba/tengine/issues/1074

 

posted on   toong  阅读(66)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具

统计

点击右上角即可分享
微信分享提示