8.5 worker进程是如何工作的

本节的内容不会涉及事件模块的处理工作,只是探讨在worker进程中循环执行的ngx_worker_process_cycle方法是如何控制进程运行的。

master进程如何通知worker进程停止服务或更换日志文件呢?对于这样控制进程运行的进程间通信方式,Nginx采用的是信号(详见14.5节)。因此,worker进程中会有一个方法来处理信号,它就是ngx_signal_handler方法。


void ngx_signal_handler(int signo)


对于worker进程的工作方法ngx_worker_process_cycle来说,它会关注以下4个全局标志位。


sig_atomic_t ngx_terminate;

sig_atomic_t ngx_quit;

ngx_uint_t ngx_exiting;

sig_atomic_t ngx_reopen;


其中的ngx_terminate、ngx_quit、ngx_reopen都将由ngx_signal_handler方法根据接收到的信号来设置。例如,当接收到QUIT信号时,ngx_quit标志位会设为1,这是在告诉worker进程需要优雅地关闭进程;当接收到TERM信号时,ngx_terminate标志位会设为1,这是在告诉worker进程需要强制关闭进程;当接收到USR1信号时,ngx_reopen标志位会设为1,这是在告诉Nginx需要重新打开文件(如切换日志文件时),见表8-3。

8.5 worker进程是如何工作的 - 图1

ngx_exiting标志位仅由ngx_worker_process_cycle方法在退出时作为标志位使用,如图8-7所示。

8.5 worker进程是如何工作的 - 图2

图 8-7 worker进程正常工作、退出时的流程图

在ngx_worker_process_cycle方法中,通过检查ngx_exiting、ngx_terminate、ngx_quit、ngx_reopen这4个标志位来决定后续动作。

如果ngx_exiting为1,则开始准备关闭worker进程。首先,根据当前ngx_cycle_t中所有正在处理的连接,调用它们对应的关闭连接处理方法(就是将连接中的close标志位置为1,再调用读事件的处理方法,在第9章中会详细讲解Nginx连接)。调用所有活动连接的读事件处理方法处理连接关闭事件后,将检查ngx_event_timer_rbtree红黑树(保存所有事件的定时器,在第9章中会介绍它)是否为空,如果不为空,表示还有事件需要处理,将继续向下执行,调用ngx_process_events_and_timers方法处理事件;如果为空,表示已经处理完所有的事件,这时将调用所有模块的exit_process方法,最后销毁内存池,退出整个worker进程。

注意 ngx_exiting标志位只有唯一一段代码会设置它,也就是下面接收到QUIT信号。ngx_quit只有在首次设置为1时,才会将ngx_exiting置为1。

如果ngx_exiting不为1,那么调用ngx_process_events_and_timers方法处理事件。这个方法是事件模块的核心方法,将会在第9章介绍它。

接下来检查ngx_terminate标志位,如果ngx_terminate不为1,则继续向下检查,否则开始准备退出worker进程。与上一步ngx_exiting为1的退出流程不同,这里不会调用所有活动连接的处理方法去处理关闭连接事件,也不会检查是否已经处理完所有的事件,而是立刻调用所有模块的exit_process方法,销毁内存池,退出worker进程。

接下来再检查ngx_quit标志位,如果标志位为1,则表示需要优雅地关闭连接。这时,Nginx首先会将所在进程的名字修改为"worker process is shutting down",然后调用ngx_close_listening_sockets方法来关闭监听的端口,接着设置ngx_exiting标志位为1,继续向下执行(检查ngx_reopen_files标志位)。

最后检查ngx_reopen标志位,如果为1,则表示需要重新打开所有文件。这时,调用ngx_reopen_files方法重新打开所有文件。之后继续下一个循环,再去检查ngx_exiting标志位。