声明:图片来自 github:https://github.com/russelltao/geektime-nginx
reload重载配置文件真相
- 之前的演示中,我们更改了nginx配置文件时,都会执行 nginx -s reload。
- 我们执行这条命令的原因是,我们希望nginx不停止服务,始终在处理新的请求的同时,把nginx配置的文件平滑地从旧的nginx.conf更新为新的nginx.conf。
- 这样一个功能对nginx非常有必要,但有时我们发现执行后,nginx的worker进程变多了。这其实是老的配置运行的nginx的worker进程长时间没有退出。当我们用stream做四层反向代理的时候,这样的场景可能更多。
reload流程
- 向master进程发送HUP信号(reload命令)
- 在我们修改nginx.conf后,向master进程发送HUP信号,这其实和我们在nginx命令行执行nginx -s reload命令是一样的。
- master进程校验配置语法是否正确
- master进程收到信号以后,master进程校验配置语法是否正确,也就是说我们并不一定非要在nginx -s reload 之前先执行 -t 检验下语法是否正确,在nginx master进程一定会做这件事情。
- master进程打开新的监听端口
- 在配置语法完全正确以后,nginx的master进程就回去打开新的监听窗口。
- 为什么要在master进程中打开新的监听窗口呢?
- 因为我们可能在nginx.conf中引入了新的例如443之前我们没有打开的监听窗口,所有的worker进程是master进程的子进程,子进程会继承父进程所有已经打开的端口,这是Linux操作系统所定义的。所以这一步master打开了可能我们引入的新地端口。
- master进程用新配置启动新的worker子进程
- master进程用新的nginx.conf配置文件启动新的worker子进程
- master进程向老worker子进程发送QUIT信号
- 在启动新的子进程以后,再向老的worker子进程发送QUIT信号,这时候我们发现QUIT信号和TERM INT信号不一样的,QUIT信号是请优雅地关闭子进程。这时,我们要注意先后顺序,因为nginx必须要保证平滑,所以它一定要先启动新的worker子进程再向老的worker子进程发送QUIT信号。
- 老worker进程关闭监听句柄,处理完当前连接后结束进程
- 老的worker子进程收到QUIT信号以后,首先关闭监听句柄,也就是说这个时候新的连接只会到新的worker子进程,所以它们之间虽然有个时间差,但是时间是非常快速的。处理完关闭监听句柄,处理完当前连接后结束进程。
- 不停机载入新配置
- 如图(从左至右看),开始master进程有四个worker进程,它们使用了老的配置。
- 当我们更改了nginx.conf配置文件以后
- 发送SIGHUP或者发送reload
- 执行reload后master会用新的配置文件启动四个(黄色的)worker子进程,所以此时是(黄色的)worker子进程和(绿色的)worker子进程是并存的,也就是说新老worker子进程是并存的
- 老的worker子进程在正常的情况下,它在会处理已经建立好的连接好饿请求以后,关闭这个连接。
- 但是异常的情况,如果有一些请求出问题了,客户端长时间没有处理,就会导致这个进程长时间占用在worker进程上面,worker进程就会一直存在。当然新的连接已经跑在(黄色的)worker子进程中了,所以影响不会很大,唯一会导致的是出问题的那个(绿色的)worker子进程长时间存在。
- 这种问题如何处理?
- 在nginx比较新的版本中,提供了一个配置项worker shutdown timeout ,也就是说最长不会等多长时间。
- mater进程在启动新的worker子进程时,会给老的worker子进程加一个定时器worker shutdown timeout ,如果时间到了老的worker子进程还没退出,就立刻强制的把老的worker子进程退出。