一、worker process简介
当我们谈论到NGINX的高性能时,不得不提到它的多进程、多线程架构。其中,worker process是NGINX多进程架构的核心,它负责接受和处理客户端的连接请求,并处理这些请求所需要的一系列操作。
在NGINX中,有一个master process和若干个worker process。其中master process主要负责初始化,然后fork出若干个worker process进行真正的请求处理。而每一个worker process都是独立的进程,可以单独对客户端进行请求响应和处理。
master_process { // 初始化工作 ...... // fork出worker process进行请求处理 for (i = 0; i < worker_processes; i++) { spawn_worker_process(); } ...... } worker_process { // 处理请求 ...... }
二、worker process的创建和销毁
正如上面的代码所示,worker process是由master process通过fork创建的。每个worker process都是一个独立的进程,有自己的进程ID以及内存空间。
当NGINX初始化完毕后,master process会根据预设的worker_process数量fork出若干个子进程,这些子进程就是我们常说的worker process。这些worker process会在某个事件被触发时响应相应的事件,并进行处理。
在NGINX的运行过程中,有时候需要动态地增减worker process的数量。这时,master process会向已有的worker process发送信号,告诉它们需要创建新的worker process。而这些新的worker process则会在另一个进程空间中进行初始化和操作。
// master process发送信号给worker process,触发创建新的worker process void ngx_signal_handler(int signo) { switch (signo) { case SIGHUP: ...... for (i = 0; i < ngx_worker_processes; i++) { ngx_pid = ngx_workers[i].pid; kill(ngx_pid, SIGQUIT); } ...... break; case SIGQUIT: ...... spawn_worker_process(); ...... break; ...... } }
三、worker process的事件处理
worker process作为NGINX的请求处理单元,是负责处理所有客户端请求的进程。因此,worker process需要处理各种各样的事件,包括网络连接事件、定时器事件、读写事件等。
在worker process的初始化过程中,会进行事件驱动机制的初始化。它会调用系统底层接口,比如epoll,select等,来监听各种事件并进行处理。
// worker process初始化事件驱动机制 void ngx_worker_process_init_cycle() { ...... // 初始化epoll系统调用接口 ngx_epoll_init(cycle); ...... // 开始监听事件 ngx_process_events_and_timers(cycle); ...... }
当worker process收到一个事件时,它会首先判断这个事件的类型,然后根据不同的类型进行相应的处理。
// 处理网络连接事件 void ngx_event_accept(ngx_event_t *rev) { ...... } // 处理读事件 void ngx_event_recv(ngx_event_t *ev, ngx_int_t flags) { ...... } // 处理定时器事件 void ngx_event_expire_timers() { ...... }
四、worker process的进程间通信
在NGINX的多进程架构中,worker process之间需要进行进程间通信,来共享一些资源或者协调某些操作。
这个进程间通信有多种方式,最常见的是信号和共享内存。
在我们刚才提到的动态增减worker process的情况下,master process会向所有已有的worker process发送SIGQUIT信号。这个信号的作用是使worker process进行优雅退出,释放资源。当worker process处理完所有已有请求后退出时,master process会fork出新的worker process,以保证NGINX的运行稳定。
// 接收SIGQUIT信号进行退出 void ngx_worker_process_cycle() { ...... for (;;) { if (ngx_quit) { ngx_worker_process_exit(); } ...... } ...... }
除了信号外,共享内存也是worker process之间通信的常用方式。比如,当多个worker process都需要访问共同的资源时,就可以使用共享内存。
// 在worker process中使用共享内存 void *ngx_shm_alloc(size_t size) { // 获取共享内存 ngx_shm_info_t *shm_info = ngx_get_shm_info(); // 分配内存 void *addr = mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, shm_info->fd, 0); ...... return addr; }
五、worker process的异常处理
在NGINX的运行过程中,worker process可能会因为一些异常情况而退出。比如,由于客户端请求过多,导致worker process阻塞无法处理请求;或者是系统内存不足导致worker process无法运行。
当worker process退出时,master process会接收到这个信号,并重新创建新的worker process。同时,master process还会将进程退出的原因记录在日志中,以帮助管理员进行故障排查。
// worker process异常退出时记录日志 void ngx_process_get_status() { ...... if (WTERMSIG(status)) { ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "%P exited on signal %d", pid, WTERMSIG(status)); } else { ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "%P exited with code %d", pid, WEXITSTATUS(status)); } ...... }
六、结语
本文深入探讨了NGINX的worker process,希望能给大家提供一些关于NGINX多进程架构的实践经验。在NGINX的运行过程中,worker process起着至关重要的作用,因此我们需要深入理解它们的工作方式,以便在实践中更好地调试和优化。