如何优雅地关闭worker进程?

武培轩 2020年02月04日 81次浏览

之前我们讲解 Nginx 命令行的时候,可以看到 Nginx 停止有两种方式,分别是 nginx -s quitnginx -s stop,其中 stop 是指立即停止 Nginx,而 quit 是指优雅的关闭 Nginx,对应的信号也是同样的,还有我们之前提到的 reload 和热升级这样的过程中都涉及到了优雅的停止 Nginx。

那所谓的优雅的停止 Nginx 究竟是怎样一个过程呢,接下来让我一起来学习下吧。

何为优雅的关闭?

所谓的优雅的关闭,是针对 worker 进程而言的,因为只有 worker 进程 才会处理请求。如果我们在处理一个连接的时候,不管连接此时对于请求是怎样一个作用,直接去关闭链接会导致用户收到错误,所以优雅地关闭就是指 Nginx 的 worker 进程 可以识别出当前连接没有正在处理请求,这个时候再把连接进行关闭。

对于某些请求 Nginx 无法做到优雅地关闭 worker 进程,比如当 Nginx 代理 websocket 协议的时候,在 websocket 后面进行通讯的 frame 桢里面,Nginx 是不解析他的桢的;Nginx 做 TCP 层或者 UDP 层反向代理的时候,也没有办法识别一个请求需要经历多少报文才算是结束;但是对于 HTTP 请求,Nginx 可以做到,所以优雅地关闭主要针对的是 HTTP 请求。

接下来我们去看一下优雅地关闭 worker 进程都有哪些流程。

优雅的关闭流程

优雅地关闭worker进程

首先第一步会设置一个定时器,在 nginx.conf 中可以配置一个 worker_shutdown_timeout,配置完 worker_shutdown_timeout 之后,会加一个标志位,表示进入优雅关闭流程了。

第二步会先关闭监听句柄,要保证所在的 worker 进程不会再去处理新的连接。

接下来会先去看连接池,因为 Nginx 为了保证对资源的利用是最大化的,经常会保存一些空闲的连接,但是没有断开,这时候会首先关闭空闲连接。

第四步是可能非常耗时的一步,因为 Nginx 不是主动的立刻关闭,是通过第一步添加的标志位,然后在循环中每当发现一个请求处理完毕,就会把这个请求使用的连接关掉,所以在循环中等待关闭所有的时间可能会很长。当设置了 worker_shutdown_timeout 的时候,即使请求还没处理完,当时间到了之后这些请求都会被强制关闭,也就是说优雅地关闭只完成了一半,有一部分连接是立即停止的。

因此在以下两个条件:当所有循环中连接被优雅地关闭,或者达到了 worker_shutdown_timeout 时间定时器以后,worker 进程都会立即退出。

总结

这篇文章主要讲解了 worker 进程优雅关闭的一个过程,很多时候我们都会用到 Nginx 优雅关闭这样一个特性,那么在这一个特性失效的时候,我们需要考虑 Nginx 有没有能力去判定一个连接此时应当被正确的关掉;或者说如果出现了错误、有些模块或者有些客户端不能正常的处理请求时,Nginx 需要有一些例外的措施,比如 worker_shutdown_timeout 来保证 Nginx 老的 worker 进程可以正常的退出掉。