首页 > 代码库 > 【Nginx】启动流程
【Nginx】启动流程
本流程从启动应用程序后的main函数开始跟踪。
解析命令行参数并保存到ngx_cycle_t结构体中,在ngx_process_options函数中将保存配置文件路径。
调用ngx_add_inherited_sockets函数获取环境变量中关于平滑升级的一些信息。平滑升级时,旧的master进程会通过环境变量发送传递一些信息给新的master进程,新的master进程启动后要去环境变量中取得这些信息,这就是这个函数的作用。
调用ngx_init_cycle初始化ngx_cycle_t结构体,其中包括:
- 调用每个核心模块的create_conf方法创建存储配置项参数的结构体。注意,非核心模块存储配置项的结构体不在这里创建,而是由核心模块负责创建。
- 调用配置模块提供的解析方法,遍历配置文件,对于每一个配置项又遍历所有核心模块,核心模块感兴趣的配置项是存放在ngx_command_t结构体中的,找出对该配置项感兴趣的合兴模块后调用ngx_command_t中定义的解析方法。
- 调用所有核心模块的init_conf方法,根据解析的配置项参数进行初始化。
- 创建并打开所需的目录和文件。
- 初始化用于进程间通信的共享内存。
- 调用ngx_open_listening_sockets函数打开由各Nginx模块从配置文件中读取到的监听端口。所有的监听端口都保存在ngx_cycle_t->listening数组中,存储元素是ngx_listening_t结构体,表示监听端口及相关参数。
- 调用所有模块的init_module方法,这个方法保存在ngx_module_t->init_module函数指针中。
如果配置文件设为单进程工作模式(master_process为off),将调用ngx_single_process_cycle函数。在该函数中调用所有模块的init_process方法,该方法保存在ngx_module_t->init_process函数指针中。系统进入单进程模循环工作。
如果配置文件设为master-worker工作模式(master_process为on),则调用ngx_master_process_cycle函数。该函数fork(封装在ngx_start_worker_processes函数中)出work子进程。work进程会进入ngx_worker_process_cycle函数。该函数首先调用ngx_worker_process_init方法,后者调用所有模块的init_process方法。然后work进程在ngx_worker_process_cycle中循环工作。
再来一张整体流程图:
worker进程工作流程
worker进程在ngx_worker_process_cycle函数的for循环中不断运行。它检查四个标志位:
- ngx_terminate:表示强制关闭进程,由信号处理函数ngx_signal_handler函数置1.
- ngx_quit:表示优雅关闭进程,由信号处理函数ngx_signal_handler函数置1.
- ngx_reopen:表示重新打开文件,由信号处理函数ngx_signal_handler函数置1.
- ngx_exiting:表示将要退出进程,仅在为0且ngx_quit被置的情况下置1.
标志位和信号对应关系如下图:
worker进程通过检查以上四个标志位来决定程序执行流。我把整个函数做了简化,代码如下:
static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) { ngx_int_t worker = (intptr_t) data; ngx_uint_t i; ngx_connection_t *c; /* 该函数内会调用所有模块的init_process方法 */ ngx_worker_process_init(cycle, worker); ... for ( ;; ) { /* 退出进程标识 */ if (ngx_exiting) { c = cycle->connections; /* 关闭所有连接 */ for (i = 0; i < cycle->connection_n; i++) { if (c[i].fd != -1 && c[i].idle) { c[i].close = 1; /* close标识置1 */ c[i].read->handler(c[i].read); /* 调用读事件处理方法 */ } } if (ngx_event_timer_rbtree.root == ngx_event_timer_rbtree.sentinel) { /* 红黑树为空,已经处理完所有事件,调用所有模块的exit_process方法 */ ngx_worker_process_exit(cycle); } } /* 还有事件需要处理,继续向下执行 */ ngx_process_events_and_timers(cycle); /* 处理事件,事件模块核心方法 */ /* 强制关闭进程 */ if (ngx_terminate) ngx_worker_process_exit(cycle); /* 直接调用所有模块的exit_process方法退出worker进程 */ /* 优雅的关闭连接 */ if (ngx_quit) { ngx_quit = 0; ngx_setproctitle("worker process is shutting down"); /* 修改进程名字 */ if (!ngx_exiting) { ngx_close_listening_sockets(cycle); /* 关闭监听句柄 */ ngx_exiting = 1; /* ngx_exiting标识唯一被修改的地方 */ } } if (ngx_reopen) { /* 重新打开所有文件 */ ngx_reopen = 0; ngx_reopen_files(cycle, -1); } } }
流程图如下:
master进程工作流程
master进程在函数ngx_master_process_cycle中不断循环,它不处理网络事件,它只是管理worker子进程。和worker进程类似,master通过监控七个标志位来决定程序执行流,这七个标志位如下所示:
以下是经过简化的ngx_master_process_cycle函数:
void ngx_master_process_cycle(ngx_cycle_t *cycle) { ... /* 根据配置文件启动worker_processes个work子进程 */ ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); /* master进程 */ for ( ;; ) { sigsuspend(&set); /* 阻塞,等待信号 */ if (ngx_reap) { ngx_reap = 0; /* 监控所有子进程,重新启动非正常退出的子进程 */ live = ngx_reap_children(cycle); } /* live为0表示所有子进程已经退出 */ if (!live && (ngx_terminate || ngx_quit)) { /* 满足上述条件,退出master进程,包括: * 1、删除存储进程的pid文件 * 2、调用所有模块的exit_master方法 * 3、关闭监听端口 * 4、销毁内存池 */ ngx_master_process_exit(cycle); } if (ngx_terminate) /* 强制关闭 */ { if (delay > 1000) { ngx_signal_worker_processes(cycle, SIGKILL); /* SIGKILL = 9 */ } else { /* NGX_TERMINATE_SIGNAL = TERM = 15 * 向每个子进程发送TERM信号 */ ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_TERMINATE_SIGNAL)); } continue; /* 跳上去挂起 */ } if (ngx_quit) /* 优雅的退出,向所有子进程发送QUIT信号 */ { ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); /* NGX_SHUTDOWN_SIGNAL = QUIT */ ls = cycle->listening.elts; /* 关闭所有端口 */ for (n = 0; n < cycle->listening.nelts; n++) ngx_close_socket(ls[n].fd); cycle->listening.nelts = 0; continue; /* 跳上去挂起 */ } if (ngx_reconfigure) /* 需要重新读取配置文件 */ { /* 重新读取配置文件后,生成新的worker进程,销毁旧的worker进程 */ ngx_reconfigure = 0; cycle = ngx_init_cycle(cycle); /* 重新配置ngx_cycle_t结构体 */ ngx_cycle = cycle; ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); /* 重新派生子进程 */ ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_JUST_RESPAWN); ngx_start_cache_manager_processes(cycle, 1); live = 1; /* 表示有子进程在运行 */ /* 向旧的子进程发送QUIT信号,要求它们退出 */ ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); } if (ngx_restart) /* 重启work进程 */ { ngx_restart = 0; ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); ngx_start_cache_manager_processes(cycle, 0); live = 1; /* 表示有子进程在运行 */ } if (ngx_reopen) /* 重新打开所有文件 */ { ngx_reopen = 0; ngx_reopen_files(cycle, ccf->user); /* 向所有子进程发送USR1信号,要求每个子进程重新打开文件 */ ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_REOPEN_SIGNAL)); } if (ngx_change_binary) /* 平滑升级 */ { ngx_change_binary = 0; ngx_new_binary = ngx_exec_new_binary(cycle, ngx_argv); /* 新的子进程启动新版本的Nginx */ } if (ngx_noaccept) /* 优雅的关闭服务 */ { ngx_noaccept = 0; ngx_noaccepting = 1; /* 向所有子进程发送QUIT信号,要求它们优雅的关闭服务 */ ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); } } }
流程图如下:
参考:
《深入理解Nginx》 P275-P286.
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。