LD is tigger forever,CG are not brothers forever, throw the pot and shine forever.
Modesty is not false, solid is not naive, treacherous but not deceitful, stay with good people, and stay away from poor people.
talk is cheap, show others the code and KPI, Keep progress,make a better result.
Survive during the day and develop at night。
目录
概 述
nginx有两类进程,一类称为master进程(相当于管理进程),另一类称为worker进程(实际工作进程)。启动方式有两种:
(1)单进程启动:此时系统中仅有一个进程,该进程既充当master进程的角色,也充当worker进程的角色。
(2)多进程启动:此时系统有且仅有一个master进程,至少有一个worker进程工作。
master进程主要进行一些全局性的初始化工作和管理worker的工作;事件处理是在worker中进行的。
2.实现原理
这里只分析多进程下的工作原理。
nginx的进程启动过程是在ngx_master_process_cycle(src/os/unix/ngx_process_cycle.c)中完成的,在ngx_master_process_cycle中,会根据配置文件的worker_processes值创建多个子进程,即一个master进程和多个worker进程。进程之间、进程与外部之间保持通信。如下图所示:图中w1表示worker进程1,以此类推。虚线表示信号通信,实现表示socketpair通信。
nginx 的进程模型采用的是prefork方式,预先分配的worker子进程数量由配置文件指定,默认为1。master主进程创建监听套接口,fork子进程以后,由worker进程监听客户连接,每个worker子进程独自尝试accept已连接套接口,accept是否上锁可以配置,默认会上锁,如果操作系统支持原子整型,才会使用共享内存实现原子上锁,否则使用文件上锁。如果不使用锁,当多个进程同时accept,当一个连接来的时候多个进程同时被唤起,会导致惊群问题。使用锁的时候,只会有一个worker阻塞在accept上,其他的进程则会不能获取锁而阻塞,这样就解决了惊群的问题。master进程通过socketpair向worker子进程发送命令,终端也可以向master发送各种命令,子进程通过发送信号给master进程的方式与其通信,worker之间通过unix套接口通信。
当master接收到worker发回的SIGCHLD信号时,(worker进程的退出信号),它会逐个检查每一个worker进程,如果发现有worker进程是异常退出,就会重新启动这个worker进程。另外nginx还有两个用于管理cache的进程,一个是cache manager process,另外一个是cache loader process,它们是专门服务于文件cache的进程,也服从master进程的管理,类似于worker进程,后面的分析将略去它们。下面从代码的角度,详细分析实现细节。
master启动的时候,有一些重要的全局数据会被设置,最重要的是进程表ngx_processes,master每创建一个worker都会把一个设置好的ngx_process_t结构变量放入ngx_processes中,新创建的进程存放在ngx_process_slot位置,ngx_last_process是进程表中最后一个存量进程的下一个位置,ngx_process_t是进程在nginx中的抽象:
复制代码
1 typedef struct {
2 ngx_pid_t pid; //进程的ID
3 int status; //进程的退出状态
4 ngx_socket_t channel[2]; //用于socketpair通信的一对socket句柄
5 ngx_spawn_proc_pt proc; //进程的执行函数
6 void *data; //proc的参数
7 char *name; //进程的title标识
8 unsigned respawn:1; //进程的状态:重新创建的
9 unsigned just_spawn:1; //进程的状态: 第一次创建的
10 unsigned detached:1; //进程的状态: 分离的,独立的
11 unsigned exiting:1; //进程的状态: 正在退出的
12 unsigned exited:1; //进程的状态: 已经退出的
13 } ngx_process_t;(src/os/unix/ngx_process.h)
复制代码
master进程向worker子进程发送命令是通过socketpair创建的一对socket实现的,之间传输的是ngx_channel_t结构变量:
复制代码
1 typedef struct {
2 ngx_uint_t command; //发送的命令
3 ngx_pid_t pid; //发送方进程的进程id
4 ngx_int_t slot; //发送方进程在进程表中偏移位置
5 ngx_fd_t fd; //发送给对方的文件句柄
6 } ngx_channel_t;(src/os/unix/ngx_channel.h)
复制代码
command是要发送的命令,有5种:
1 #define NGX_CMD_OPEN_CHANNEL 1
2 #define NGX_CMD_CLOSE_CHANNEL 2
3 #define NGX_CMD_QUIT 3
4 #define NGX_CMD_TERMINATE 4
5 #define NGX_CMD_REOPEN 5
1).首先分析master进程的代码的功能,(Ngx_process_cycle.c中):
main()函数首先做一系列的初始化工作调用各模块的初始化代码(例如创建监听套接口等)然后就会调用ngx_master_process_cycle代码(多进程启动情况下),cycle是一个全局结构体变量,存储有系统运行的所需要的一些信息。在分析进程关系的的时候可以先忽略它。
小结
参考资料和推荐阅读
1.链接: 参考资料.