【NGINX进程模型】源码分析
2017-07-05 00:00
489 查看
本文主要用于个人笔记整理,以此抛砖引玉,阐述过程未免会有所疏漏,希望此文能获得相关领域专家的指正和建议。
内容概要
本章主要分析nginx进程之间的关系、进程职责和进程启动的过程,Nginx 启动的时候一般是一个master进程和多个工作进程,可以通过一下配置设置工作进程的个数:
master进程的职责是接收外界信号、管理工作进程;work进程的职责是处理用户请求。下图是nginx进程模型核心函数,如图1-1(请自行在新窗口打开):
图1-1:nginx进程模型函数调用
一、主入口函数(省略部分初始化代码,以下类同)
主入口函数是ngx_master_process_cycle,该方法主要用于启动工作进程、如果设置了缓存,还用于启动缓存管理进程;启动完工作进程后,主函数会挂起监听外界信号。
ngx_master_process_cycle方法的核心逻辑是通过调用方法ngx_start_worker_processes启动工作进程;调用方法ngx_start_cache_manager_processes用于启动缓存管理进程;调用sigsuspend用于挂起master进程监听外界信号,当有外界信号时,master进程会暂停,等待ngx_signal_handler去处理信号。
二、循环创建工作线程
ngx_start_worker_processes方法是通过主函数ngx_master_process_cycle调用的方法,用于遍历用户设置的工作进程数<worker_processes 8>创建工作进程:
如果用户设置worker_processes为8,则对应上述代码中n=8,改代码主要调用了两个方法,ngx_spawn_process用于fork工作进程,ngx_pass_open_channel用于将新创建的进程信息通过master进程传递给已创建的进程。
三、创建具体工作进程
工作进程的创建包括socketpair,fork,proc(ngx_spawn_proc_pt)这几个核心方法:
其中socketpair用于创建可以相互通信的套接字对;fork这个方法会将master进程拷贝一份成工作进程,当然中间还有些操作在下文具体阐释;proc实际类型是ngx_worker_process_cycle,该方法用于执行创建好的进程。
① socketpair
顾名思义,创建一对相同的匿名scoket套接字,他们之间可以相互通信,其中一个套接字指定给父进程使用,另外一个给子进程,父子进程之间就可以通信。该方法原型如下:
② fork
通过系统调用创建一个和当前进程完全一样的进程:
fork和socketpair一起使用,其中一个套接字给父类,另外一个套接字给子类,就可以实现父子进程的双向通信,例如:如果父进程调用scoketpair创建了一对套接字(F1,F2),在调用fork后,会生成子进程,那么子进程也继承了父类的匿名套接字(Z1,Z2),如果父进程使用F1(sv[0].channel),那么子进程就使用Z2(sv[1].channel),这样就必须关闭F2和Z1。
③ proc(ngx_worker_process_cycle)
该方法用于启动创建好的工作进程:
四、传递子进程信息
子进程之间相互传递信息是为了子进程之间的通信,但目前来说,子进程之间通过亲缘的socket套接字通信的方式还没有使用到,这种通信方式主要用于master和work之间的信息传递:
以上代码中,会遍历当前存活的工作进程数,将新创建的进程信息ch,包括pid、socket套接字等信息传递给其他进程,执行过程也是通过父类进程channel[0]进行消息传递给其余子进程。在ngx_worker_process_init中会将channel和回调函数ngx_channel_handler关联,但channel中有数据传递过来,就会触发回调函数的调用。所以此处执行ngx_write_channel实际上是执行回调函数ngx_channel_handler:
该函数内有大概5个不同的case语句:
我们当前使用到了NGX_CMD_OPEN_CHANNEL,即最开始的ngx_pass_open_channel方法调用。
五、cache进程的创建就不在赘述了,方法如上。
内容概要
本章主要分析nginx进程之间的关系、进程职责和进程启动的过程,Nginx 启动的时候一般是一个master进程和多个工作进程,可以通过一下配置设置工作进程的个数:
worker_processes 8;
master进程的职责是接收外界信号、管理工作进程;work进程的职责是处理用户请求。下图是nginx进程模型核心函数,如图1-1(请自行在新窗口打开):
图1-1:nginx进程模型函数调用
一、主入口函数(省略部分初始化代码,以下类同)
主入口函数是ngx_master_process_cycle,该方法主要用于启动工作进程、如果设置了缓存,还用于启动缓存管理进程;启动完工作进程后,主函数会挂起监听外界信号。
void ngx_master_process_cycle(ngx_cycle_t *cycle) { // 清空信号集,用于接收新的信号 sigemptyset(&set); // 省略添加信号的方法,xxx代表SIGCHLD,SIGALRM,SIGIO等 sigaddset(&set, xxx); // 开始启动工作线程 ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); // 开始启动cache管理进程 ngx_start_cache_manager_processes(cycle, 0); //挂起进程监听外界信息(kill –QUIT `cat /data/logs/nginx.pid`) sigsuspend(&set); }
ngx_master_process_cycle方法的核心逻辑是通过调用方法ngx_start_worker_processes启动工作进程;调用方法ngx_start_cache_manager_processes用于启动缓存管理进程;调用sigsuspend用于挂起master进程监听外界信号,当有外界信号时,master进程会暂停,等待ngx_signal_handler去处理信号。
二、循环创建工作线程
ngx_start_worker_processes方法是通过主函数ngx_master_process_cycle调用的方法,用于遍历用户设置的工作进程数<worker_processes 8>创建工作进程:
static void ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type) { // 根据配置创建n个进程 for (i = 0; i < n; i++) { // 开始fork()工作线程 // ngx_worker_process_cycle用于启动进程,即 proc(cycle, data); ngx_spawn_process(cycle, ngx_worker_process_cycle, (void *) (intptr_t) i, "worker process", type); // 将创建的子进程相关信息传递已经创建的进程 //ch中包含了进程的pid,slot,fd等信息 // 其中channel就是一个能够存储2个整型元素的数组而已, // 这个channel数组就是用于socketpair函数创建一个进程间通道之用的 ngx_pass_open_channel(cycle, &ch); }
如果用户设置worker_processes为8,则对应上述代码中n=8,改代码主要调用了两个方法,ngx_spawn_process用于fork工作进程,ngx_pass_open_channel用于将新创建的进程信息通过master进程传递给已创建的进程。
三、创建具体工作进程
工作进程的创建包括socketpair,fork,proc(ngx_spawn_proc_pt)这几个核心方法:
ngx_pid_t ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data, char *name, ngx_int_t respawn) { // 创建一对socket套接字 socketpair(AF_UNIX, SOCK_STREAM, 0, ngx_processes[s].channel) // fork进程 pid = fork(); // 执行fork成功的进程 proc(cycle, data); }
其中socketpair用于创建可以相互通信的套接字对;fork这个方法会将master进程拷贝一份成工作进程,当然中间还有些操作在下文具体阐释;proc实际类型是ngx_worker_process_cycle,该方法用于执行创建好的进程。
① socketpair
顾名思义,创建一对相同的匿名scoket套接字,他们之间可以相互通信,其中一个套接字指定给父进程使用,另外一个给子进程,父子进程之间就可以通信。该方法原型如下:
/** * *domain-套接口的域 *type-套接口类型 *protocol-使用的协议 *sv[2]-指向存储文件描述符的指针 */ int socketpair(int domain, int type, int protocol, int sv[2]);
② fork
通过系统调用创建一个和当前进程完全一样的进程:
/** * @return * 父类中调用返回pid>0,则pid为子类pid * 子类中调用返回pid=0,则表示当前是子类 * 返回的pid=-1,表示fork失败 */ pid = fork();
fork和socketpair一起使用,其中一个套接字给父类,另外一个套接字给子类,就可以实现父子进程的双向通信,例如:如果父进程调用scoketpair创建了一对套接字(F1,F2),在调用fork后,会生成子进程,那么子进程也继承了父类的匿名套接字(Z1,Z2),如果父进程使用F1(sv[0].channel),那么子进程就使用Z2(sv[1].channel),这样就必须关闭F2和Z1。
③ proc(ngx_worker_process_cycle)
该方法用于启动创建好的工作进程:
static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) { // 启动前先初始化一些参数,比如 // 设置环境变量、设置资源限制,绑定cpu等 ngx_worker_process_init(cycle, worker); // 启动for循环处理事件 for ( ;; ) { // 阻塞等待事件发生 ngx_process_events_and_timers(cycle); } }
四、传递子进程信息
子进程之间相互传递信息是为了子进程之间的通信,但目前来说,子进程之间通过亲缘的socket套接字通信的方式还没有使用到,这种通信方式主要用于master和work之间的信息传递:
static void ngx_pass_open_channel(ngx_cycle_t *cycle, ngx_channel_t *ch) { for (i = 0; i < ngx_last_process; i++) { ngx_write_channel(ngx_processes[i].channel[0], ch, sizeof(ngx_channel_t), cycle->log); } }
以上代码中,会遍历当前存活的工作进程数,将新创建的进程信息ch,包括pid、socket套接字等信息传递给其他进程,执行过程也是通过父类进程channel[0]进行消息传递给其余子进程。在ngx_worker_process_init中会将channel和回调函数ngx_channel_handler关联,但channel中有数据传递过来,就会触发回调函数的调用。所以此处执行ngx_write_channel实际上是执行回调函数ngx_channel_handler:
static void ngx_channel_handler(ngx_event_t *ev) { switch (ch.command) { case NGX_CMD_OPEN_CHANNEL: // 保存新进程的pid ngx_processes[ch.slot].pid = ch.pid; // 保存文件描述符 ngx_processes[ch.slot].channel[0] = ch.fd; break; // 一堆case语句,将在以后的文章中体现 } }
该函数内有大概5个不同的case语句:
// 打开channel,即创建子进程的操作 #define NGX_CMD_OPEN_CHANNEL 1 // 关闭已经打开过的channel #define NGX_CMD_CLOSE_CHANNEL 2 // 优雅的退出命令 #define NGX_CMD_QUIT 3 // 强制退出命令 #define NGX_CMD_TERMINATE 4 //重新打开之前打开又关闭的文件 #define NGX_CMD_REOPEN 5
我们当前使用到了NGX_CMD_OPEN_CHANNEL,即最开始的ngx_pass_open_channel方法调用。
五、cache进程的创建就不在赘述了,方法如上。
相关文章推荐
- Nginx源码分析 ——Nginx的进程模型
- nginx源码分析--高性能服务器开发 常见进程模型
- nginx 源码分析 进程模型
- nginx源码分析(3)——进程模型
- nginx源码分析--master和worker进程模型
- nginx源码分析--master和worker进程模型
- nginx源码分析(3)——进程模型
- nginx源码分析--框架设计 & master-worker进程模型
- nginx源码分析--高性能服务器开发 常见进程模型
- nginx源码分析(3)——进程模型
- nginx进程间的通信机制源码分析(一)----共享内存
- nginx源码分析(4)——事件模型
- nginx源码分析1———进程间的通信机制六(UNIX域协议)
- Nginx源码分析—worker进程的创建
- Nginx源码分析--master进程
- Nginx源码分析--master和worker进程间的通信
- Nginx源码分析:3张图看懂启动及进程工作原理
- nginx 源码分析阅读笔记-进程管理
- Nginx源码分析-master和worker进程间的通信
- nginx源码分析1———进程间的通信机制二(自旋锁)