NGINX的平滑重启和平滑升级

3,272 阅读4分钟

一、NGINX平滑重启

Nginx的reload的“平滑升级”或者“热更新”其实是“升级”/“更新”的配置,例如upstream中扩容新的实例,而不是Nginx自身进程升级到了新的版本。所以这种reload其实应该叫“平滑重启”。注意,NGINX的架构是master+worker模式,这个平滑重启,重启的是worker进程,master并没有重启。重启的基本原理是:master监听系统信号,如果master监听到系统信号HUP后,重新load配置文件(会先检查配置文件的有效性,如果无效退出“平滑重启”,保持原样),创建若干个新的worker进程N,这些新的worker进程会用新的配置启动,注意这些新的worker进程依然是监听原来的port,此时有2N+1(master也在监听,但是master不处理客户端连接请求)个进程在监听原来的port(update20210401需要注意的是,NGINX是父子进程模型,子进程继承了父进程的所有内容,因此子进程也会监听这个port,不会存在端口被占用的问题。而且,子进程其实没有执行bind操作,只有父进程才会进行bind操作,所以,不会有端口被占用的问题。),然后master向旧的进程发送信号,优雅停机(先关闭端口监听,然后处理完滞留的请求后退出)。最后依然是N+1个进程。详细过程参考:

平滑重启:

  • 只是向新的master发送HUP信号,这样就会重新读取配置启动若干新的worker子进程。
  • 最后master向旧的worker发送信号优雅停机这些worker子进程。

二、NGINX平滑升级

NGINX平滑升级是指升级nginx到新的二进制文件,如从1.0升级到2.0,这个过程不会停止对外提供服务,又不会对当前的请求造成影响。nginx通过信号的方式进行热升级。先用新版本的二进制文件覆盖旧版本的二进制文件,对master进程发送USER2信号,master会fork出新的子进程(这个子进程是新版本的master进程),该新的master进程读取新的配置创建它的新的子进程。注意,新的master由于是旧的master的子进程,共享了原来进程的ServerSocket,所以没有出现Address already in use 错误。这时系统存在着2*(N+1)个进程处理请求。这时像旧的master进程发送WINCH信号,使旧的master进程像其原来的N个子进程发送信号,让旧的N个子进程关闭ServerSocket停止监听,处理完滞留请求后退出。此时系统存在着N+1+1个进程(新旧master同时存在)。然后再向旧的master发送QUIT信号,使旧的进程退出。此时系统存在着N+1个进程。整体过程详见:

热升级比较复杂(update20210401):

  • 向旧的master进程发送USER2信号,会创建出新的master进程
  • 当新的master进程启动新的worker进程之后,向旧的master进程发送WINCH信号,杀死旧的worker进程
    • 如果新的master、worker正常工作的话,向旧的master进程发送QUIT信号,旧的master退出,完成升级。
    • 如果新的master、worker不正常
      • 可以向旧的master发送HUP信号,让旧的master启动一批worker进程(还是旧的配置),之后向新的master进程发送QUIT信号,让新的master和新的worker退出。
      • 也可以向新的master发送TERM信号,这样新的master、worker直接退出。之后旧的master自动启动新的worker进程。

三、总结

可以发现NGINX的平滑升级完全是基于新旧进程的继承机制实现的,兼容性较好。没有进行任何的socket文件描述符的迁移、传递。

Nginx的worker进程在退出的时候,给客户端返回的时候,传递了一个让客户端关闭连接的控制指令,这是HTTP协议的一个特性。否则,如果是长连接的话,旧的worker进程永远都不能退出了。

参考

硬广告

欢迎关注公众号:double6