Nginx启动以及IOCP模型Word文档格式.docx
- 文档编号:17622121
- 上传时间:2022-12-07
- 格式:DOCX
- 页数:38
- 大小:30.78KB
Nginx启动以及IOCP模型Word文档格式.docx
《Nginx启动以及IOCP模型Word文档格式.docx》由会员分享,可在线阅读,更多相关《Nginx启动以及IOCP模型Word文档格式.docx(38页珍藏版)》请在冰豆网上搜索。
,发现在/src/core/nginx.c中,代码大概如下:
intngx_cdeclmain(intargc,char*const*argv){
...//先是一些变量声明
ngx_debug_init();
...
ngx_pid=ngx_getpid();
init_cycle.pool=ngx_create_pool(1024,log);
cycle=ngx_init_cycle(&
init_cycle);
if(ngx_signal){
returnngx_signal_process(cycle,ngx_signal);
}
if(ngx_create_pidfile(&
ccf->
pid,cycle->
log)!
=NGX_OK){
return1;
if(ngx_process==NGX_PROCESS_SINGLE){
ngx_single_process_cycle(cycle);
}else{
ngx_master_process_cycle(cycle);
return0
这段代码大致看上去,先是做了一些初始化的事情,包括pool看起来应该是内存池之类的变量的分配,获取系统信息,
初始化日志系统等等,因为还没有进入相应函数去仔细看,所以先放着。
用过nginx的同学应该了解,nginx命令行
运行./nginx后,他直接就运行服务了,很静默,然后即使用Ctrl+C也关不掉。
但是再开一个console,运行
./nginx-h就会看到:
nginxversion:
nginx/1.11.7
Usage:
nginx[-?
hvVtTq][-ssignal][-cfilename][-pprefix][-gdirectives]
Options:
-?
-h:
thishelp
-v:
showversionandexit
-V:
showversionandconfigureoptionsthenexit
-t:
testconfigurationandexit
-T:
testconfiguration,dumpitandexit
-q:
suppressnon-errormessagesduringconfigurationtesting
-ssignal:
sendsignaltoamasterprocess:
stop,quit,reopen,reload
-pprefix:
setprefixpath(default:
NONE)
-cfilename:
setconfigurationfile(default:
conf/nginx.conf)
-gdirectives:
setglobaldirectivesoutofconfigurationfile
这是nginx的命令行参数介绍,要退出nginx需要用nginx-sstop给已经打开的nginx进程发送信号,让其退出。
而且nginx还支持平滑的重启,这种重启在更改nginx配置时非常有用,重启服务器的过程,实际上是nginx自己内部
的一种处理,重新载入新的配置,但是却不影响已经有的一些连接,所以称之为平滑重启。
gracefullystopnginx…
而main函数在初始化之后,做的就是命令行参数的解析,如果是显示版本,那么显示一个版本信息,就退出;
如果是设置
配置文件,那么去调用设置配置文件的相应处理;
如果是发送控制信号,那么returnngx_signal_process(cycle,ngx_signal);
处理信号等等。
这里还有个小trick,就是关于pid文件,程序把自己的pid写入一个文件,然后就可以防止启动多个进程,
这是一个比较常用的小技巧。
关于ngx_single_process_cycle(cycle)这应该是单进程的情况,一般而言现在的服务器
都是多核为主,所以我们去ngx_master_process_cycle(cycle)Master进程的主函数看一看。
主进程
ngx_master_process_cycle函数在/src/os/win32/ngx_process_cycle.c中,该函数接受一个参数,这个参数比较
复杂,但是可以看出,应该是和每次nginx循环的生命周期有关,这里认为nginx每平滑重启一次,就是一次循环。
代码
分为几个部分来看:
voidngx_master_process_cycle(ngx_cycle_t*cycle){
if(ngx_process==NGX_PROCESS_WORKER){
//ngx_process标识进程的身份,如果本进程应该是工作者进程,就去执行工作者应该做的
ngx_worker_process_cycle(cycle,ngx_master_process_event_name);
return;
SetEnvironmentVariable("
ngx_unique"
ngx_unique);
//设置环境变量,表示nginx主进程已经运行
ngx_master_process_event=CreateEvent(NULL,1,0,ngx_master_process_event_name);
if(ngx_master_process_event==NULL){
ngx_log_error(NGX_LOG_ALERT,cycle->
log,ngx_errno,
"
CreateEvent(\"
%s\"
)failed"
ngx_master_process_event_name);
exit
(2);
if(ngx_create_signal_events(cycle)!
ngx_sprintf((u_char*)ngx_cache_manager_mutex_name,
ngx_cache_manager_mutex_%s%Z"
ngx_cache_manager_mutex=CreateMutex(NULL,0,
ngx_cache_manager_mutex_name);
if(ngx_cache_manager_mutex==NULL){
CreateMutex(\"
ngx_cache_manager_mutex_name);
events[0]=ngx_stop_event;
events[1]=ngx_quit_event;
events[2]=ngx_reopen_event;
events[3]=ngx_reload_event;
ngx_close_listening_sockets(cycle);
if(ngx_start_worker_processes(cycle,NGX_PROCESS_RESPAWN)==0){
}
理解这段代码,需要了解Windows系统的一点点事件相关API,CreateEvent可以创建一个事件,之后可以通过一些方法
比如SetEvent可以使得这个事件被激活,进程或者线程也可以通过WaitForSingleObejct等API去等待一个事件的发
生。
这段代码就是创建了一些事件,包括stop,quit,reopen和reload,这些事件是在ngx_create_signal_events
函数中创建的:
staticngx_int_t
ngx_create_signal_events(ngx_cycle_t*cycle)
{
ngx_sprintf((u_char*)ngx_stop_event_name,
Global\\ngx_stop_%s%Z"
ngx_stop_event=CreateEvent(NULL,1,0,ngx_stop_event_name);
if(ngx_stop_event==NULL){
ngx_stop_event_name);
returnNGX_ERROR;
ngx_sprintf((u_char*)ngx_quit_event_name,
Global\\ngx_quit_%s%Z"
...
之后,主进程调用ngx_close_listening_sockets(cycle)关闭正在侦听的套接字,这样之后的连接就不会进来了,
因为主进程循环肯定是重启或者初始化的时候被调用的。
之后调用ngx_start_worker_processes函数去启动工作者
线程。
我们看看ngx_start_worker_process函数,同样在这个文件里:
ngx_start_worker_processes(ngx_cycle_t*cycle,ngx_int_ttype)
ngx_int_tn;
ngx_core_conf_t*ccf;
ngx_log_error(NGX_LOG_NOTICE,cycle->
log,0,"
startworkerprocesses"
);
ccf=(ngx_core_conf_t*)ngx_get_conf(cycle->
conf_ctx,ngx_core_module);
for(n=0;
n<
ccf->
worker_processes;
n++){
if(ngx_spawn_process(cycle,"
worker"
type)==NGX_INVALID_PID){
break;
returnn;
这个函数先是读取了本次循环的配置,根据配置中的worker_process的设置来启动相应数量的工作者进程,配置文件
在/conf/nginx.conf中:
#usernobody;
worker_processes8;
#error_loglogs/error.log;
#error_loglogs/error.lognotice;
#error_loglogs/error.loginfo;
#pidlogs/nginx.pid;
events{
worker_connections65536;
当然如果配置文件中没有设置,以及新创建的配置文件中如何设置默认值,这些都在/src/core/nginx.c中,但是不是
非常重要,所以暂时略过。
回归ngx_master_process_cycle函数,该函数在创建了事件之后,会进入一个死循环:
for(;
;
){
nev=4;
ngx_last_process;
if(ngx_processes[n].handle){
events[nev++]=ngx_processes[n].handle;
if(timer){
timeout=timer>
ngx_current_msec?
timer-ngx_current_msec:
0;
ev=WaitForMultipleObjects(nev,events,0,timeout);
err=ngx_errno;
ngx_time_update();
ngx_log_debug1(NGX_LOG_DEBUG_CORE,cycle->
log,0,
masterWaitForMultipleObjects:
%ul"
ev);
if(ev==WAIT_OBJECT_0){
exiting"
if(ResetEvent(ngx_stop_event)==0){
ResetEvent(\"
if(timer==0){
timer=ngx_current_msec+5000;
ngx_terminate=1;
ngx_quit_worker_processes(cycle,0);
continue;
if(ev==WAIT_OBJECT_0+1){
shuttingdown"
if(ResetEvent(ngx_quit_event)==0){
ngx_quit_event_name);
ngx_quit=1;
if(ev>
WAIT_OBJECT_0+3&
&
ev<
WAIT_OBJECT_0+nev){
ngx_log_debug0(NGX_LOG_DEBUG_CORE,cycle->
reapworker"
live=ngx_reap_worker(cycle,events[ev]);
if(!
live&
(ngx_terminate||ngx_quit)){
ngx_master_process_exit(cycle);
if(ev==WAIT_TIMEOUT){
ngx_terminate_worker_processes(cycle);
if(ev==WAIT_FAILED){
log,err,
WaitForMultipleObjects()failed"
WaitForMultipleObjects()returnedunexpectedvalue%ul"
首先介绍WaitForMultipleObjects,这个函数会等待多个内核对象,可以是事件,也可以是锁,进程等等。
这个循环中,每次
循环先添加了ngx_last_process个进程到了事件数组中,这个ngx_processes大概是上次循环中使用的进程组。
如果定义的
stop,quit,reload,reopen四种事件触发,分别调用相关函数去关闭或者重启工作者进程。
如果是上次循环中使用的进
程死亡,那么就去重启这个进程,调用ngx_reap_worker函数,这个函数在确认旧的进程已经死亡后,会调用ngx_spawn_process
去重启一个新的进程。
ngx_spawn_process会调用ngx_execute去开一个新的进程,这部分的细节,放入下一节再讲。
这样我们
了解了主进程在启动后,会进入事件处理循环来处理nginx-s发送的指令以及处理进程组死亡的重启。
那么我们看看工作者进程
是做什么的。
工作者进程
我们了解到,主进程调用ngx_start_worker_process函数根据配置文件启动多个工作者进程,这个函数中调用了ngx_spawn_process
来启动新的工作者进程,那么我们来看看ngx_spawn_process是如何启动一个新的进程。
以下是部分代码(位于/src/os/win32/ngx_process.c):
ngx_pid_tngx_spawn_process(ngx_cycle_t*cycle,char*name,ngx_int_trespawn){
...//变量定义
//第一次主循环传入的是NGX_PROCESS_JUST_RESPAWN==-3
if(respawn>
=0){
s=respawn;
for(s=0;
s<
s++){
if(ngx_processes[s].handle==NULL){
if(s==NGX_MAX_PROCESSES){
nomorethan%dprocessescanbespawned"
NGX_MAX_PROCESSES);
returnNGX_INVALID_PID;
//得到Nginx的文件路径
n=GetModuleFileName(NULL,file,MAX_PATH);
if(n==0){
GetModuleFileName()failed"
file[n]='
\0'
ctx.path=file;
pid=ngx_execute(cycle,&
ctx);
//创建新进程
这部分是先找到ngx_process中的索引,然后放入一个新的进程,那么我们看看ngx_execute函数是怎么执行的:
ngx_pid_tngx_execute(ngx_cycle_t*cycle,ngx_exec_ctx_t*ctx)
if(CreateProcess(ctx->
path,ctx->
args,
NULL,NULL,0,CREATE_NO_WINDOW,NULL,NULL,&
si,&
pi)
==0)
{
ngx_log_error(NGX_LOG_CRIT,cycle->
CreateProcess(\"
ngx_argv[0]);
return0;
ctx->
child=pi.hProcess;
if(CloseHandle(pi.hThread)==0){
CloseHandle(pi.hThread)failed"
start%sprocess%P"
ctx->
name,pi.dwProcessId);
returnpi.dwProcessId;
这个函数通过调用ngx_execute开启新的进程,并把进程句柄存入了context中,返回pid。
创建系统进程之后,会调用
WaitForMultipleObjects等待两个事件,一个是ngx_master_process_event,这个事件在主进程循环中定义,另一
个是新开的进程死亡。
如果主进程事件触发,那么会使用OpenEvent设置新进程的事件为以前创建的事件。
但是可能是因为
我手头的版本还在开发中,我没有在代码里面找到
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Nginx 启动 以及 IOCP 模型