三:深入理解Nginx的模块化 (结合源码详解)
2016-06-20 10:56
471 查看
盗用前面用到的流程图
第二步实际上是调用
Nginx在不重启服务升级,旧版本的
3~8步都在
调用配置模块提供的解析配置项方法 。遍历
调用所有的
之前第四步在 解析配置项时,所有的模块都已经解析出自己需要监听的端口 ,如HTTP模块 已经 在 解析http{…}配置项时得到要监听的端口 ,并添加到listening数组中。这一步骤就是按照listening数组中的每一个
在这个阶段会调用所有模块的
接下来流程可以参考之前的博客nginx代码分析
第二步实际上是调用
ngx_add_inherited_sockets()
//文件名: Nginx.c int ngx_cdecl main(int argc, char *const *argv) { ... if (ngx_add_inherited_sockets(&init_cycle) != NGX_OK) { return 1; } ... }
Nginx在不重启服务升级,旧版本的
master进程会通过
execve系统调用来启动新版本的
master进程(先 fork()出子进程再调用exec来运行新程序),这时旧版本 的
master进程通过 环境变量通知新版本的
master这是在升级,新版本的
master进程通过
ngx_add_inherited_sockets()方法 由环境变量里读取平滑升级信息,并对旧版本Nginx服务监听 的句柄做继承处理 。
3~8步都在
ngx_init_cycle()方法中执行的。在初始化
ngx_cycle_t中所有的容器后,会为读取、解析文件 做准备工作。因为每个 模块都必须有相应的数据结构来 存储配置文件中的各配置项,创建这些数据结构的工作都需要在这一步进行。Nginx框架只关心
NGX_CORE_MODULE核心模块,从而降低框架的复杂度,这里将会调用所有核心模块的
create_conf的方法(也只有核心模块才有这个方法 ),这意味着所有核心模块开始构造用于存储配置项的结构体。非核心模块将由每个模块进行管理,如 HTTP模块都由
ngx_http_module管理。这样
ngx_http_module在解析自己感兴趣的”http”配置项时,将会调用所有HTTP模块 约定的方法来 创建存储配置的结构体
//文件名 ngx_cycle.h typedef struct ngx_cycle_s ngx_cycle_t; struct ngx_cycle_s { void ****conf_ctx; // 配置上下文数组(含所有模块) ngx_pool_t *pool; // 内存池 ngx_log_t *log; // 日志 ngx_log_t new_log; ngx_connection_t **files; // 连接文件 ngx_connection_t *free_connections; // 空闲连接 ngx_uint_t free_connection_n; // 空闲连接个数 ngx_module_t **modules; ngx_uint_t modules_n; ngx_uint_t modules_used; /* unsigned modules_used:1; */ ngx_queue_t reusable_connections_queue; // 再利用连接队列 ngx_array_t listening; // 监听套接字数组 ngx_array_t pathes; // 路径数组 ngx_list_t open_files; // 打开文件链表 ngx_list_t shared_memory; // 共享内存链表 ngx_uint_t connection_n; // 连接个数 ngx_uint_t files_n; // 打开文件个数 ngx_connection_t *connections; // 连接 ngx_event_t *read_events; // 读事件 ngx_event_t *write_events; // 写事件 ngx_cycle_t *old_cycle; // old cycle指针 ngx_str_t conf_file; // 配置文件 ngx_str_t conf_param; // 配置参数 ngx_str_t conf_prefix; // 配置文件目录 ngx_str_t prefix; // 程序工作目录 ngx_str_t lock_file; // 锁文件,用在不支持accept_mutex的系统中 ngx_str_t hostname; // 主机名 };
调用配置模块提供的解析配置项方法 。遍历
nginx.conf的所有配置项,对于任一配置项,将会检查所有核心模块以找出对它所感兴趣的模块。并调用该模块在
ngx_command_t结构体中的定义的 配置项处理办法 。
调用所有的
NGX_CORE_MODULE核心模块的
init_conf的 方法。这一步骤的 目的在于让所有核心模块在解析完配置项可以做综合性处理。
之前第四步在 解析配置项时,所有的模块都已经解析出自己需要监听的端口 ,如HTTP模块 已经 在 解析http{…}配置项时得到要监听的端口 ,并添加到listening数组中。这一步骤就是按照listening数组中的每一个
ngx_listening_t元素设置socket句柄并监听端口,实际上就是调用
ngx_open_listening_sockets()。
在这个阶段会调用所有模块的
init_module方法。接下来 就是根据 配置Nginx运行模式决定如何工作。
接下来流程可以参考之前的博客nginx代码分析
worker进程工作流程
master采用的是信号的方式通知worker进程停止服务或更换日志。在函数
ngx_worker_process_cycle()通过检查
ngx_exiting、ngx_terminate、ngx_quit、ngx_reopen这4个标志位来决定后续动作。
master进程工作流程
master进程不需要处理网络事件,不负责业务的执行,只会通过该管理
worker等子进程来实现重启服务、平滑升级、更换日志文件、配置文件实时生效等 功能 。
master进程中所有子进程相关的状态信息都保存在ngx_processes数组中,下面 是数组元素的类型
ngx_process_t的 结构的定义,代码如下 :
typedef struct { //进程 ID ngx_pid_t pid; // 由waitpid系统调用获取到进程状态 int status; // 这是由socketpair系统调用产生出用于进程 间通信 的socket句柄 ngx_socket_t channel[2]; // 子进程的循环执行的办法,当父进程调用ngx_spawn_process 生成子进程时使用 ngx_spawn_proc_pt proc; void *data; // 进程名称。操作系统中显示的进程名称与name相同 char *name; // 标志位,为1时表示在重新生成子进程 unsigned respawn:1; // 标志位, 为1时表示正在 生成子进程 unsigned just_spawn:1; // 标志位,为1时表示在父进程、子进程分离 unsigned detached:1; // 标志位,为1时表示进程正在退出 unsigned exiting:1; // 标志位,为1时表示进程已经退出 unsigned exited:1; } ngx_process_t;
ngx_spawn_process方法封装了
fork系统调用,并且会从
ngx_processes数组中选择一个还未使用的
ngx_process_t元素存储这个子进程的相关信息。
相关文章推荐
- CentOS6.5使用yum命令方便快捷安装Nginx
- 使用Nginx+FFMPEG搭建HLS直播转码服务器
- nginx 安装
- nginx 安装
- nginx 负载均衡,多站点共享Session
- Centos6.5源码编译安装nginx
- 如何调用Sphinx
- nginx图片服务器nginx.conf配置
- nginx常用命令
- 【 Linux 】lvs-dr模型实现HA,后端Nginx、PHP、MySQL分离 搭建wordpress站点
- nginx之常用内置变量,命令及配置
- nginx之root和alias两种命令的区别
- nigix配置成功,但是不能访问
- Nginx高可用使用Keepalived+nginx实现
- centos nginx 1.6.3安装过程(带waf)
- nginx+uwsgi部署django
- Nginx安装配置
- Nginx负载均衡配置
- nginx内置预定义变量
- 在阿里云服务器上配置CentOS+Nginx+Python+Flask环境