Nginx源码分析——master进程与worker进程(一)

一、说明

 

从默认的情况下分析,nginx启动之后会分别有一个master进程与一个worker进程
从上一章,了解到整个main函数的执行流程之后,我们就知道下面函数
ngx_master_process_cycle(cycle);
是启动master进程与worker进程的核心函数。
还有根据还是的知识,master进程与worker进程的职能分工入下
了解这些这后,我们继续深入的去看ngx_master_process_cycle 函数到底在做什么?
二、函数分析
开始的变量申明就先不讲了。
sigemptyset(&set);

set是一个sigset_t的数据结构,系统自带的。这里是将信号清空。

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));
将SIGCHLD SIGALRM SIGIO等等信号,增加到&set中去。具体为什么这里设置了信号,后面又要清空掉,后面在讨论。
if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) {
    ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                "sigprocmask() failed");
}

将&set数组里面的信息进行屏蔽。

sigemptyset(&set);

清空信号

size = sizeof(master_process);

for (i = 0; i < ngx_argc; i++) {
    size += ngx_strlen(ngx_argv[i]) + 1;
}

在上文提到过,main函数在执行ngx_save_argv,将参数信息保存到ngx_argv数组里面,这样来设置size的大小,size为后面进程显示用。

title = ngx_pnalloc(cycle->pool, size);
if (title == NULL) {
    /* fatal */
    exit(2);
}

为title申请内存块,内存块大小是否大于最大的内存块,若大于则使用大块内存的分配。

p = ngx_cpymem(title, master_process, sizeof(master_process) - 1);
for (i = 0; i < ngx_argc; i++) {
    *p++ = ' ';
    p = ngx_cpystrn(p, (u_char *) ngx_argv[i], size);
}
ngx_setproctitle(title);

设置title,nginx的作者为了性能也是拼了,一般我们写这个真不会写的这么复杂。类似可以看到如下这样的title

master process ./sbin/nginx
ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);

获取配置

ngx_start_worker_processes(cycle, ccf->worker_processes,
                            NGX_PROCESS_RESPAWN);

启动worker进程,worker进程的数量跟worker_processes设置的数量有关系。ngx_spawn_process函数组装创建逻辑,会循环调用多次。ngx_worker_process_cycle是worker进程处理事件,并且将accept事件和read、write事件分开队列进行处理。并且将进程创建的事件广播出去。这块后续会深入的去分析。//TODO

ngx_start_cache_manager_processes(cycle, 0);

启动的缓存模块,之后会生存这样一个进程,专门来处理。

在nginx.conf文件中中,配置了proxy_cache_path就会启动这个进程,如果没有配置就没有这个进程。具体内容后面再去讨论。//TODO
    ngx_new_binary = 0;
    delay = 0;
    sigio = 0;
    live = 1;


    for ( ;; ) {
        if (delay) {
            if (ngx_sigalrm) {
                sigio = 0;
                delay *= 2;
                ngx_sigalrm = 0;
            }


            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                           "termination cycle: %M", delay);


            itv.it_interval.tv_sec = 0;
            itv.it_interval.tv_usec = 0;
            itv.it_value.tv_sec = delay / 1000;
            itv.it_value.tv_usec = (delay % 1000 ) * 1000;


            if (setitimer(ITIMER_REAL, &itv, NULL) == -1) {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                              "setitimer() failed");
            }
        }


        ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "sigsuspend");


        sigsuspend(&set);


        ngx_time_update();


        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                       "wake up, sigio %i", sigio);


        if (ngx_reap) {
            ngx_reap = 0;
            ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap children");


            live = ngx_reap_children(cycle);
        }


        if (!live && (ngx_terminate || ngx_quit)) {
            ngx_master_process_exit(cycle);
        }


        if (ngx_terminate) {
            if (delay == 0) {
                delay = 50;
            }


            if (sigio) {
                sigio--;
                continue;
            }


            sigio = ccf->worker_processes + 2 /* cache processes */;


            if (delay > 1000) {
                ngx_signal_worker_processes(cycle, SIGKILL);
            } else {
                ngx_signal_worker_processes(cycle,
                                       ngx_signal_value(NGX_TERMINATE_SIGNAL));
            }


            continue;
        }


        if (ngx_quit) {
            ngx_signal_worker_processes(cycle,
                                        ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
            ngx_close_listening_sockets(cycle);


            continue;
        }


        if (ngx_reconfigure) {
            ngx_reconfigure = 0;


            if (ngx_new_binary) {
                ngx_start_worker_processes(cycle, ccf->worker_processes,
                                           NGX_PROCESS_RESPAWN);
                ngx_start_cache_manager_processes(cycle, 0);
                ngx_noaccepting = 0;


                continue;
            }


            ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring");


            cycle = ngx_init_cycle(cycle);
            if (cycle == NULL) {
                cycle = (ngx_cycle_t *) ngx_cycle;
                continue;
            }


            ngx_cycle = cycle;
            ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx,
                                                   ngx_core_module);
            ngx_start_worker_processes(cycle, ccf->worker_processes,
                                       NGX_PROCESS_JUST_RESPAWN);
            ngx_start_cache_manager_processes(cycle, 1);


            /* allow new processes to start */
            ngx_msleep(100);


            live = 1;
            ngx_signal_worker_processes(cycle,
                                        ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
        }


        if (ngx_restart) {
            ngx_restart = 0;
            ngx_start_worker_processes(cycle, ccf->worker_processes,
                                       NGX_PROCESS_RESPAWN);
            ngx_start_cache_manager_processes(cycle, 0);
            live = 1;
        }


        if (ngx_reopen) {
            ngx_reopen = 0;
            ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs");
            ngx_reopen_files(cycle, ccf->user);
            ngx_signal_worker_processes(cycle,
                                        ngx_signal_value(NGX_REOPEN_SIGNAL));
        }


        if (ngx_change_binary) {
            ngx_change_binary = 0;
            ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "changing binary");
            ngx_new_binary = ngx_exec_new_binary(cycle, ngx_argv);
        }


        if (ngx_noaccept) {
            ngx_noaccept = 0;
            ngx_noaccepting = 1;
            ngx_signal_worker_processes(cycle,
                                        ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
        }
    }

一个无条件的循环,处理输入的信号,之前也说过,master进程就是专门来处理各种命令的。先对master进程处理信号这块进行解读。

三、总结
Nginx所有进程的启动都是在函数ngx_master_process_cycle中完成的,包括master进程、worker进程和Cache进程,整体代码上还是比较清晰的,还有对各个进程需要处理事件的,也在这个过程中做了定义,就是最后一块master进程的无条件循环出现在这里感觉上不是特别好看,不过也是比较容易懂的。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sinom21

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值