java架构师培训:Nginx是怎样实现 “平滑”升级的?

2021年01月13日 20:01

25

    实现层面分析Nginx到底是如何执行平滑升级的,这样就可以快速定位热升级时可能遇到的问题。


    平滑升级涉及两个关键的子功能,一是在收到USR2信号后,启动新版本Nginx;二是将不再监听端口的nginx进程优雅退出。先来看USR2信号的处理。


    在Linux中,使用fork函数就可以生成子进程副本,再用execve函数载入新版本的nginx二进制文件运行,就进入新老版本nginx并存的阶段。此时,写入master进程pid的nginx.pid文件内容会发生变化(了解了这一点就清楚找不到nginx.pid文件后,nginx的命令行为何不再生效)。


    由于nginx支持通过命令行发送信号,比如上文介绍过的热加载,其实与向master进程发送HUP信号是完全一致的。但日常我们更习惯通过更方便的nginx-sreload命令行来完成,reload命令在读取nginx.pid文件中的进程id后,就会向master进程发送HUP信号。

640 (1).png

    在升级过程中新版本的nginx启动后,nginx.pid中只会存放新master进程的id,而老master进程的id则会改放在nginx.pid.oldbin文件中。


    当老版本的master进程优雅退出后,nginx.pid.oldbin文件会被自动删除。这些细节可以协助分析热升级时遇到的问题。


    再来看nginx是如何优雅退出的,即worker进程怎样判定所有TCP连接都处理完了。当master进程收到QUIT或者WINCH信号后,会向所有worker子进程发送QUIT信号。而worker进程收到QUIT信号后,会做以下4件事:

640.png


    1、设置worker_shutdown_timeout定时器,因为有些应用协议nginx并不解析,也就无从判断何时会结束。比如,使用stream模块做四层负载均衡,或者用作七层的websocket反向代理时,nginx都无法判断何时该关闭连接。因此,旧版本的nginx进程会长时间存在。设置定时器后,worker进程会在worker_shutdown_timeout秒后强行退出。当然,通常情况下不需要配置worker_shutdown_timeout,因为老worker进程长时间存在并不会影响新nginx的业务。


    2、关闭监听着的所有端口;


    3、关闭所有空闲的TCP连接;


    4、设置ngx_exiting标志位为1(协助业务模块关闭连接),等待业务模块关闭所有的TCP连接后,自行退出进程。比如对于HTTP短连接请求而言(即HTTP头部中存在Connection:closed),当nginx发送完响应后就可以主动关闭TCP连接。如果是HTTP长连接(即存在Connection:keep-alive头部),正常情况下应当由客户端关闭连接,或者连接上处理过的请求个数超过了keepalive_request_count才能由nginx关闭连接,但在优雅退出这个场景中,nginx可以在处理完当前http请求后立刻关闭连接,如下代码所示:


    if(!ngx_terminate


    &&!ngx_exiting//在优雅退出时,ngx_exiting会置为1


    &&r->keepalive


    &&clcf->keepalive_timeout>0)


    {


    ngx_http_set_keepalive(r);//作为HTTP长连接继续复用


    return;


    }


    worker进程正是按照这样的优雅退出流程自行关闭的。热重载新的nginx.conf配置文件时也使用了优雅退出这一功能,如下图所示:

5c5958f14da5fef9290dfda5d6bd7744.png


  推荐阅读:jvm培训:如何判断哪些对象需要回收?


更多鲁班学院java高级培训免费课程试听地址https://www.lubanjava.com/course.html

鲁班学院java高级培训课程https://www.lubanjava.com/course/detail/519.html

加群即可领取鲁班学院最新Java高级培训课程资料学习包 群号:700541970



咨询(2)
免费试听
领取优惠
加群交流

扫一扫
加群领取架构师资料

售后反馈
返回顶部