一、进程结构
nginx有两种进程结构:多进程结构、单进程结构。
单进程结构的地址空间在线程之间是共享的,所以一旦有一个线程崩了,就会导致整个nginx不可用,所以默认的nginx都是多进程的,单进程只适合我们在本地开发时使用。
nginx多进程的结构如图1所示:
图1
- master进程是主进程,它的作用是管理worker进程,主要是检测worker进程是否正常运行、是否需要重新启动配置文件、是否需要热部署等。master进程默认是允许加入第三方模块代码的,但是非常不建议这么做,因为一旦第三方模块出错,将会导致整个nginx不可用,
- CM(Cache Manager):缓存的管理。周期性的启动,检查告诉缓存的状态,
- CL(Cache Loader):缓存的载入。写入缓存时启动,写完关闭,时间很短。
- Worker:Worker进程是真正用来处理请求的进程。缓存要在多个Worker进程之间共享,并且还要被CM、CL使用。
这些进程间的通信都是使用共享内存进行的。
二、为什么要有多个Worker进程
nginx采用事件驱动之后,希望每一个worker进程都对应一个CPU,所以worker进程要配置的和服务器上的CPU核数一致,并且每一个worker进程都要与某一个CPU进行绑定,这样可以更好的使用每一个CPU上面的CPU缓存。
master进程不消耗CPU。
三、多进程查看、操作
1、查看
启动nginx,使用ps -ef | grep nginx查看nginx进程,如图2所示,关于nginx的进程有两个,一个是master进程,一个是worker进程。
图2
master进程的id为12492,worker进程的id为17355,worker进程的父进程为12492,即worker进程由master进程所创建。
2、reload
使用./sbin.nginx -s reload重新加载配置文件时,原来的worker进程会被关闭,master进程会新创建一个worker进程,该worker进程的id为17372。
图3
除了使用reload重新加载配置文件之外,我们还可以向master发送SIGHUP信号,通知master进程重新reload,比如我们使用kill -SIGHUP 12492,发送之后,我们查看nginx进程,如图4,发现原来17373的worker进程没有了,多了一个17405的worker进程。
图4
使用SIGHUP信号和reload的作用是一模一样的,都是优雅的关闭之前的worker进程。
3、SIGTERM
当我们使用SIGTERM关闭worker进程时,会先向master进程发送一个SIGCHILD信号,然后worker进程关闭,但是master进程会为了保持固定的worker进程数,再重新创建一个新的worker进程。
四、使用信号管理父子进程
在nginx中能够发送接收信号的有master进程、worker进程、nginx命令行。
1、master进程
a、监控worker进程
master进程能够启动worker进程,所以master进程会监控worker进程是否发送CHILD信号,当发送CHILD进程时,就说明worker进程将要关闭,那么master进程就会重新的拉起一个worker进程。
b、管理worker进程
master进程可以接收信号用来管理worker进程。
c、接收信号
-
TERM,INT:立刻停止worker进程。
-
QUIT:优雅的停止worker进程,也就是慢慢的停,要保证不会向用户发送立刻结束连接的报文。
-
HUP:重载配置文件。
-
USR1:重新打开日志文件。
-
USR2、WINCH:在热部署时使用到。
2、worker进程
同master进程的接收信号,但是不建议对worker进程发起信号,因为希望由master进程去管理worker进程。
3、nginx命令行
启动一个命令行后,nginx会将master进程的pid记录到logs/nginx.pid文件中,当我们使用nginx -s *这类命令行时,nginx的工具命令行会读取nginx.pid中的master的pid,然后想该pid发送HUP等信号。
所以直接使用reload等命令和使用kill发送信号的作用是一样的。
四、优雅的关闭
优雅的关闭就是慢慢的关闭,用户不会收到错误。
优雅的关闭主要针对的是HTTP请求,因为对于HTTP请求,nginx可以知道一个请求要经历多少的报文,才算是请求结束。
优雅的关闭的流程:
-
设置一个定时器:worker_shutdown_timeout。
-
关闭监听句柄,比如监听的是80端口,那么此时就会关闭80端口的监听句柄,不会在处理80端口的新的请求。
-
关闭空闲的连接池,因为nginx为了保证对资源的利用是最大化的,会在连接池中保存一些空闲连接,并且这些连接没有断开,所以在这一步它会先关闭所有的空闲连接。
-
在循环中等待全部连接关闭。在循环中,每当一个连接请求完毕,它就会关闭该连接。
-
退出进程。当所有的请求都处理关闭时,会关闭进程;当worker_shutsown_timeout设置的时间到了,会关闭进程。
优雅的关闭时针对于HTTP请求的,其他的是没有办法进行优雅的关闭的,比如webscoket。