nginx进程模型
来源:互联网 发布:360n5手机怎么样 知乎 编辑:程序博客网 时间:2024/05/22 05:06
一、介绍
nginx的核心进程采用的是master-worker进程。一个master进程(监控进程)和多个worker进程(工作进程)。
master进程:
1、fork出子进程(工作进程)。
2、接受来自外界的信号。
3、监控worker进程的工作状态,向worker进程发送信号,控制worker的运行状态。
4、当worker因某种原因退出时,及时启动worker进程。
5、监听端口,把监听句柄交给worker进程。
woker进程:
1、accept新的连接。
2、接收并处理数据。
3、接收来自master的进程控制。
二、进程控制(热重启)
nginx通过nginx -s 命令去控制进程的运行,nginx -s 是向master主进程发送命令,然后master主进程去控制子进程。nginx执行命令的
时候,会获取到nginx的安装目录下的 nginx/logs/nginx.pid 文件,里面保存着master进程ID,然后通过kill 向 master发送进程控制命令。
具体的代码如下:
1、执行main函数(src/core/nginx.c)
int ngx_cdeclmain(int argc, char *const *argv){ ... //1、ngx_get_options获取命令参数并解析 if (ngx_get_options(argc, argv) != NGX_OK) { return 1; } ... //2、执行信号处理函数ngx_signal_process,ngx_signal会在ngx_get_options赋值 if (ngx_signal) { return ngx_signal_process(cycle, ngx_signal); //直接执行然后return } ...}//ngx_get_options获取并解析命令static ngx_int_tngx_get_options(int argc, char *const *argv){ ... case 's': //ngx_signal 赋值 if (*p) { ngx_signal = (char *) p; } else if (argv[++i]) { ngx_signal = argv[i]; } else { ngx_log_stderr(0, "option \"-s\" requires parameter"); return NGX_ERROR; } //命令字符串对比 if (ngx_strcmp(ngx_signal, "stop") == 0 || ngx_strcmp(ngx_signal, "quit") == 0 || ngx_strcmp(ngx_signal, "reopen") == 0 || ngx_strcmp(ngx_signal, "reload") == 0) { ngx_process = NGX_PROCESS_SIGNALLER; //NGX_PROCESS_SIGNALLER宏定义为2,作用是为了标示nginx不是第一次启动而是nginx已经启动了, //有些操作没有必须要重复去做,主要在ngx_cycle_init初始化的时候使用 goto next; } ...}2、执行ngx_signal_process(),主要实现读取当前nginx的master进程pid。然后发送命令。
ngx_int_tngx_signal_process(ngx_cycle_t *cycle, char *sig){ ... //读取log文件中的nginx.pid ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); ngx_memzero(&file, sizeof(ngx_file_t)); file.name = ccf->pid; file.log = cycle->log; file.fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, NGX_FILE_DEFAULT_ACCESS); if (file.fd == NGX_INVALID_FILE) { ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, ngx_open_file_n " \"%s\" failed", file.name.data); return 1; } n = ngx_read_file(&file, buf, NGX_INT64_LEN + 2, 0);//读取nginx.pid文件 if (ngx_close_file(file.fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, ngx_close_file_n " \"%s\" failed", file.name.data); } if (n == NGX_ERROR) { return 1; } while (n-- && (buf[n] == CR || buf[n] == LF)) { /* void */ } pid = ngx_atoi(buf, ++n); //获取进程ID if (pid == NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, cycle->log, 0, "invalid PID number \"%*s\" in \"%s\"", n, buf, file.name.data); return 1; } //执行系统信号处理 return ngx_os_signal_process(cycle, sig, pid);}3、然后执行 ngx_os_signal_process(cycle, sig, pid),通过kill 发送命令ngx_int_tngx_os_signal_process(ngx_cycle_t *cycle, char *name, ngx_int_t pid){ ngx_signal_t *sig; for (sig = signals; sig->signo != 0; sig++) { //遍历nginx命令与进程控制命令关系表 if (ngx_strcmp(name, sig->name) == 0) { if (kill(pid, sig->signo) != -1) { //发给master命令。signals在文件中有定义如下 return 0; } ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "kill(%P, %d) failed", pid, sig->signo); } } return 1;}//signalsngx_signal_t signals[] = { { ngx_signal_value(NGX_RECONFIGURE_SIGNAL), "SIG" ngx_value(NGX_RECONFIGURE_SIGNAL), "reload", ngx_signal_handler }, { ngx_signal_value(NGX_REOPEN_SIGNAL), "SIG" ngx_value(NGX_REOPEN_SIGNAL), "reopen", ngx_signal_handler }, { ngx_signal_value(NGX_NOACCEPT_SIGNAL), "SIG" ngx_value(NGX_NOACCEPT_SIGNAL), "", ngx_signal_handler }, { ngx_signal_value(NGX_TERMINATE_SIGNAL), "SIG" ngx_value(NGX_TERMINATE_SIGNAL), "stop", ngx_signal_handler }, { ngx_signal_value(NGX_SHUTDOWN_SIGNAL), "SIG" ngx_value(NGX_SHUTDOWN_SIGNAL), "quit", ngx_signal_handler }, { ngx_signal_value(NGX_CHANGEBIN_SIGNAL), "SIG" ngx_value(NGX_CHANGEBIN_SIGNAL), "", ngx_signal_handler }, { SIGALRM, "SIGALRM", "", ngx_signal_handler }, { SIGINT, "SIGINT", "", ngx_signal_handler }, { SIGIO, "SIGIO", "", ngx_signal_handler }, { SIGCHLD, "SIGCHLD", "", ngx_signal_handler }, { SIGSYS, "SIGSYS, SIG_IGN", "", SIG_IGN }, { SIGPIPE, "SIGPIPE, SIG_IGN", "", SIG_IGN }, { 0, NULL, "", NULL }};至此执行nginx -s 的命令通过以上逻辑就发给了master主进程。下面看一下master主进程如何处理接受到的命令的。
voidngx_master_process_cycle(ngx_cycle_t *cycle){ ... //加入信号命令集 sigemptyset(&set); sigaddset(&set, SIGCHLD); sigaddset(&set, SIGALRM); sigaddset(&set, SIGIO); sigaddset(&set, SIGINT); sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_NOACCEPT_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_TERMINATE_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL)); ... //死循环等待信号 for ( ;; ) { ... //阻塞等待信号,接收到信号之后会执行绑定好的ngx_singal_hander函数 sigsuspend(&set); if (ngx_terminate) {...} //nginx -s stop if (ngx_quit) {...} //nginx -s quit if (ngx_restart) {...} //nginx -s restart if (ngx_reconfigure) {...} //nginx -s reload ... }}
master如何控制woker进程master是通过管道单向给woker发送数据的。1、先看一下channel的结构体
typedef struct { ngx_uint_t command; //发给worker的具体命令 ngx_pid_t pid; //woker的进程pid ngx_int_t slot; //woker在ngx_process数组的下标,所有的进程都会保存到ngx_process数组中。 ngx_fd_t fd; //文件描述,master有可能会把文件描述符告诉worker,让worker操作,先大致了解。} ngx_channel_t;2、master如何发送channel
static voidngx_signal_worker_processes(ngx_cycle_t *cycle, int signo){ //定义channel结构体 ngx_channel_t ch; ch.command = 0; switch (signo) { case ngx_signal_value(NGX_SHUTDOWN_SIGNAL): ch.command = NGX_CMD_QUIT; break; case ngx_signal_value(NGX_TERMINATE_SIGNAL): ch.command = NGX_CMD_TERMINATE; break; case ngx_signal_value(NGX_REOPEN_SIGNAL): ch.command = NGX_CMD_REOPEN; break; default: ch.command = 0; } ... if (ch.command) { //发送命令 ngx_write_channel 会调用sendMsg发送数据 if (ngx_write_channel(ngx_processes[i].channel[0], &ch, sizeof(ngx_channel_t), cycle->log) == NGX_OK) { if (signo != ngx_signal_value(NGX_REOPEN_SIGNAL)) { ngx_processes[i].exiting = 1; } continue; } } ...}3、worker如何接收channel
worker会把channel加入epoll中,当有channel来的时候,会触发ngx_channel_handler函数。执行ngx_worker_process_init() 通过ngx_add_channel_event()把事件加入epoll,并绑定事件处理函数ngx_channel_handler。ngx_channel_handler函数负责将一些变量置位,在woker的for(;;)中去读变量。static voidngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker){ ... //加入epoll if (ngx_add_channel_event(cycle, ngx_channel, NGX_READ_EVENT, ngx_channel_handler) == NGX_ERROR) { exit(2); } ...}static voidngx_channel_handler(ngx_event_t *ev){ ... //置位相应的标志位 switch (ch.command) { case NGX_CMD_QUIT: ngx_quit = 1; break; case NGX_CMD_TERMINATE: ngx_terminate = 1; break; case NGX_CMD_REOPEN: ngx_reopen = 1; break; ...}static voidngx_worker_process_cycle(ngx_cycle_t *cycle, void *data){ ... //worker主循环,思路同master基本一样 for (;;) { if (ngx_terminate) {...} //nginx -s stop if (ngx_quit) {...} //nginx -s quit if (ngx_restart) {...} //nginx -s restart if (ngx_reconfigure) {...} //nginx -s reload }}至此从发送一个nginx -s 命令后,nginx的master进程和worker进程都做了什么事情,以及master如何控制woker,大致原理就这些。后续如果有需要热重启的或者采用master-woker进程的,可以参考nginx的进程模型。三、惊群现象(worker)
阅读全文
0 0
- nginx的进程模型
- nginx的进程模型
- Nginx 进程模型
- 进程模型--nginx
- nginx进程模型
- nginx进程模型
- nginx核心进程模型
- Nginx进程模型
- nginx中的进程模型
- Nginx进程模型
- Nginx的进程模型
- nginx进程模型
- nginx的进程模型
- nginx进程模型
- nginx核心进程模型
- nginx的进程模型
- nginx进程模型
- nginx进程模型,事件模型
- Android源码APK剥离到eclipse调试运行教程
- Preference相关学习
- 互联网行业岗位职责
- 浅谈.net remoting 与 webservice
- openwrt上移植NFS服务器
- nginx进程模型
- 浅析Java中的final关键字
- 反向投影误差的计算
- 面---经2
- windows批处理中的%errorlevel%与!errorlevel!
- nginx内存管理
- resetTemplate的GET请求返回值为带泛型的类型list<>
- 磁性吸附
- Sublime Text 3 import Anaconda 无法正常补全模块名解决办法
原创粉丝点击
热门IT博客
热门问题
老师的惩罚
人脸识别
我在镇武司摸鱼那些年
重生之率土为王
我在大康的咸鱼生活
盘龙之生命进化
天生仙种
凡人之先天五行
春回大明朝
姑娘不必设防,我是瞎子
客厅欧式装修效果图
欧式电视背墙效果图
装修欧式风格图片
简欧客厅窗帘
简欧窗帘效果图
简欧客厅效果图
简欧电视墙效果图
室内欧式风格装修图片
圆门装修效果图
现代简欧
现代简欧风格装修
现代简欧装修
简欧风格家装
现代简欧电视背景墙效果图
装修简欧风格
现代简欧风格
简欧装修风格
简欧别墅
简欧窗帘
简欧衣柜
简欧风格电视背景墙
简欧效果图
简欧家装
现代简欧家具
简欧影视墙
简欧装修效果图
现代简欧电视墙
简欧风格装修要多少钱
后现代简欧装修风格
简欧厨房
时尚简约
简欧室内装修
简欧酒柜
样板房家具
简欧儿童房
简欧吊顶
现代简欧装修效果图
简欧书房
简欧风格装修案例
简欧风格装修电视墙
简欧装修样板间