1. 程式人生 > >三:深入理解Nginx的模組化 (結合原始碼詳解)

三:深入理解Nginx的模組化 (結合原始碼詳解)

盜用前面用到的流程圖
nginx_process

第二步實際上是呼叫 ngx_add_inherited_sockets()

//檔名: Nginx.c

int ngx_cdecl
main(int argc, char *const *argv)
{
 ...

    if (ngx_add_inherited_sockets(&init_cycle) != NGX_OK) {
        return 1;
    }

 ...
}

Nginx在不重啟服務升級,舊版本的master程序會通過execve系統呼叫來啟動新版本的master程序(先 fork()出子程序再呼叫exec來執行新程式),這時舊版本 的master

程序通過 環境變數通知新版本的master這是在升級,新版本的master程序通過 ngx_add_inherited_sockets()方法 由環境變數裡讀取平滑升級資訊,並對舊版本Nginx服務監聽 的控制代碼做繼承處理 。

3~8步都在 ngx_init_cycle()方法中執行的。在初始化ngx_cycle_t中所有的容器後,會為讀取、解析檔案 做準備工作。因為每個 模組都必須有相應的資料結構來 儲存配置檔案中的各配置項,建立這些資料結構的工作都需要在這一步進行。Nginx框架只關心NGX_CORE_MODULE核心模組,從而降低框架的複雜度,這裡將會呼叫所有核心模組的create_conf

的方法(也只有核心模組才有這個方法 ),這意味著所有核心模組開始構造用於儲存配置項的結構體。非核心模組將由每個模組進行管理,如 HTTP模組都由ngx_http_module管理。這樣ngx_http_module在解析自己感興趣的”http”配置項時,將會呼叫所有HTTP模組 約定的方法來 建立儲存配置的結構體

//檔名 ngx_cycle.h
typedef struct ngx_cycle_s       ngx_cycle_t;
struct ngx_cycle_s {
    void                  ****conf_ctx;                       // 配置上下文陣列(含所有模組)
ngx_pool_t *pool; // 記憶體池 ngx_log_t *log; // 日誌 ngx_log_t new_log; ngx_connection_t **files; // 連線檔案 ngx_connection_t *free_connections; // 空閒連線 ngx_uint_t free_connection_n; // 空閒連線個數 ngx_module_t **modules; ngx_uint_t modules_n; ngx_uint_t modules_used; /* unsigned modules_used:1; */ ngx_queue_t reusable_connections_queue; // 再利用連線佇列 ngx_array_t listening; // 監聽套接字陣列 ngx_array_t pathes; // 路徑陣列 ngx_list_t open_files; // 開啟檔案連結串列 ngx_list_t shared_memory; // 共享記憶體連結串列 ngx_uint_t connection_n; // 連線個數 ngx_uint_t files_n; // 開啟檔案個數 ngx_connection_t *connections; // 連線 ngx_event_t *read_events; // 讀事件 ngx_event_t *write_events; // 寫事件 ngx_cycle_t *old_cycle; // old cycle指標 ngx_str_t conf_file; // 配置檔案 ngx_str_t conf_param; // 配置引數 ngx_str_t conf_prefix; // 配置檔案目錄 ngx_str_t prefix; // 程式工作目錄 ngx_str_t lock_file; // 鎖檔案,用在不支援accept_mutex的系統中 ngx_str_t hostname; // 主機名 };

呼叫配置模組提供的解析配置項方法 。遍歷nginx.conf的所有配置項,對於任一配置項,將會檢查所有核心模組以找出對它所感興趣的模組。並呼叫該模組在 ngx_command_t 結構體中的定義的 配置項處理辦法 。
呼叫所有的NGX_CORE_MODULE核心模組的init_conf的 方法。這一步驟的 目的在於讓所有核心模組在解析完配置項可以做綜合性處理。
之前第四步在 解析配置項時,所有的模組都已經解析出自己需要監聽的埠 ,如HTTP模組 已經 在 解析http{…}配置項時得到要監聽的埠 ,並新增到listening陣列中。這一步驟就是按照listening陣列中的每一個 ngx_listening_t元素設定socket控制代碼並監聽埠,實際上就是呼叫ngx_open_listening_sockets()
在這個階段會呼叫所有模組的 init_module方法。接下來 就是根據 配置Nginx執行模式決定如何工作。
接下來流程可以參考之前的部落格nginx程式碼分析

worker程序工作流程

master採用的是訊號的方式通知worker程序停止服務或更換日誌。在函式ngx_worker_process_cycle()通過檢查ngx_exiting、ngx_terminate、ngx_quit、ngx_reopen這4個標誌位來決定後續動作。
worker_process

master程序工作流程

master程序不需要處理網路事件,不負責業務的執行,只會通過該管理worker等子程序來實現重啟服務、平滑升級、更換日誌檔案、配置檔案實時生效等 功能 。
master程序中所有子程序相關的狀態資訊都儲存在ngx_processes陣列中,下面 是陣列元素的型別ngx_process_t的 結構的定義,程式碼如下 :

typedef struct {
    //程序 ID
    ngx_pid_t           pid;
    // 由waitpid系統呼叫獲取到程序狀態
    int                 status;
    // 這是由socketpair系統呼叫產生出用於程序 間通訊 的socket控制代碼
    ngx_socket_t        channel[2];
    // 子程序的迴圈執行的辦法,當父程序呼叫ngx_spawn_process  生成子程序時使用
    ngx_spawn_proc_pt   proc;
    void               *data;
    // 程序名稱。作業系統中顯示的程序名稱與name相同
    char               *name;
    // 標誌位,為1時表示在重新生成子程序
    unsigned            respawn:1;
    // 標誌位, 為1時表示正在 生成子程序
    unsigned            just_spawn:1;
    // 標誌位,為1時表示在父程序、子程序分離
    unsigned            detached:1;
    // 標誌位,為1時表示程序正在退出
    unsigned            exiting:1;
    // 標誌位,為1時表示程序已經退出
    unsigned            exited:1;
} ngx_process_t;

ngx_spawn_process方法封裝了fork系統呼叫,並且會從ngx_processes陣列中選擇一個還未使用的ngx_process_t元素儲存這個子程序的相關資訊。
master_process