1. 程式人生 > >nginx程序管理之master程序

nginx程序管理之master程序

nginx分為single和 master兩種程序模型。master模型為一個master模型和n個worker程序的工作方式 。本文分析nginx的 master程序做了哪些事情,它是如何管理好各個worker程序的。

在main函式中完成了nginx啟動初始化過程,啟動初始化過程中的一個重要環節就是解析配置檔案,回撥各個配置指令的回撥函式,因此完成了各個模組的配置相互關聯。在完成初始化後,就呼叫ngx_master_process_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));

    if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) {
        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                      "sigprocmask() failed");
    }
上面遮蔽一系列的訊號,以防建立worker程序時,被打擾。
    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);
    ngx_start_cache_manager_processes(cycle, 0);
這裡開始建立worker子程序,master程序就是通過依次呼叫這兩個函式來建立子程序。第一個呼叫的函式建立的子程序稱為worker程序,第二個呼叫的函式建立的就是有關cache的子程序。接收請求,完成響應的就是worker程序。
    for (i = 0; i < n; i++) {

        ngx_spawn_process(cycle, ngx_worker_process_cycle,
                          (void *) (intptr_t) i, "worker process", type);

        ch.pid = ngx_processes[ngx_process_slot].pid;
        ch.slot = ngx_process_slot;
        ch.fd = ngx_processes[ngx_process_slot].channel[0];

        ngx_pass_open_channel(cycle, &ch);
    }
此處就是迴圈建立n個worker程序,fork新程序的具體工作在ngx_spawn_process函式中完成。這裡涉及到一個全域性陣列ngx_processes(src/os/unix/ngx_process.c),陣列的長度為NGX_MAX_PROCESSES(預設為 1024),儲存的元素型別是ngx_process_t(src/os/uninx/ngx_process.h檔案)。全域性陣列ngx_processes就是用來儲存每個子程序的相關資訊,如pid,channel,程序做具體事情的介面指標等,這 些資訊就是用結構體ngx_process_t來描述的。在ngx_spawn_process建立好一個worker程序返回 後,master程序就將worker程序的pid,worker程序在ngx_processes陣列中的位置及channel[0]傳遞給前面建立好的worker程序,然後迴圈建立下一個worker程序。channel是用socketpair建立的,用於程序間通訊。master和worker程序以及worker程序之間都可以通過這樣的一個通道進行通訊。

ngx_start_cache_manager_processes函式和start_worker的工作相關無幾。接著master程序就陷入死迴圈中守護著worker程序。在master_cycle中呼叫了sigsuspend,因而master程序掛起,等待訊號的產生(收到訊號,呼叫訊號處理函式,設定對應的全域性變數,sigsuspend函式返回,判斷全域性變數並採取相應的動作)

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

            ls = cycle->listening.elts;
            for (n = 0; n < cycle->listening.nelts; n++) {
                if (ngx_close_socket(ls[n].fd) == -1) {
                    ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
                                  ngx_close_socket_n " %V failed",
                                  &ls[n].addr_text);
                }
            }
            cycle->listening.nelts = 0;

            continue;
        }
對SIGQUIT訊號進行的處理動作。呼叫ngx_signal_worker_processes函式向每個worker程序遞送SIGQUIT訊號,通知worker程序退出工作,然後關閉所有的監聽套接字。用continue是為了子程序傳送SIGCHLD訊號給master程序,讓master程序為其善後。 
        if (ngx_reap) {
            ngx_reap = 0;
            ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap children");

            live = ngx_reap_children(cycle);
        }
此時,ngx_reap為1,master程序呼叫ngx_reap_children處理所有的worker程序。

master程序就這些。