盜用前面用到的流程圖
第二步實際上是調用 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 ;
}
...
}
Nginx在不重新開機服務更新,舊版本的程序會通過
master
系統調用來啟動新版本的
execve
程序(先 fork()出子程序再調用exec來運作新程式),這時舊版本 的
master
程序通過 環境變量通知新版本的
master
這是在更新,新版本的
master
程序通過
master
方法 由環境變量裡讀取平滑更新資訊,并對舊版本Nginx服務監聽 的句柄做繼承處理 。
ngx_add_inherited_sockets()
3~8步都在方法中執行的。在初始化
ngx_init_cycle()
中所有的容器後,會為讀取、解析檔案 做準備工作。因為每個 子產品都必須有相應的資料結構來 存儲配置檔案中的各配置項,建立這些資料結構的工作都需要在這一步進行。Nginx架構隻關心
ngx_cycle_t
核心子產品,進而降低架構的複雜度,這裡将會調用所有核心子產品的
NGX_CORE_MODULE
的方法(也隻有核心子產品才有這個方法 ),這意味着所有核心子產品開始構造用于存儲配置項的結構體。非核心子產品将由每個子產品進行管理,如 HTTP子產品都由
create_conf
管理。這樣
ngx_http_module
在解析自己感興趣的”http”配置項時,将會調用所有HTTP子產品 約定的方法來 建立存儲配置的結構體
ngx_http_module
//檔案名 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數組中的每一個
元素設定socket句柄并監聽端口,實際上就是調用
ngx_listening_t
ngx_open_listening_sockets()
。
在這個階段會調用所有子產品的
init_module
方法。接下來 就是根據 配置Nginx運作模式決定如何工作。
接下來流程可以參考之前的部落格nginx代碼分析
worker程序工作流程
master
采用的是信号的方式通知worker程序停止服務或更換日志。在函數
ngx_worker_process_cycle()
通過檢查
ngx_exiting、ngx_terminate、ngx_quit、ngx_reopen
這4個标志位來決定後續動作。
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[];
// 子程序的循環執行的辦法,當父程序調用ngx_spawn_process 生成子程序時使用
ngx_spawn_proc_pt proc;
void *data;
// 程序名稱。作業系統中顯示的程序名稱與name相同
char *name;
// 标志位,為1時表示在重新生成子程序
unsigned respawn:;
// 标志位, 為1時表示正在 生成子程序
unsigned just_spawn:;
// 标志位,為1時表示在父程序、子程序分離
unsigned detached:;
// 标志位,為1時表示程序正在退出
unsigned exiting:;
// 标志位,為1時表示程序已經退出
unsigned exited:;
} ngx_process_t;
方法封裝了
ngx_spawn_process
系統調用,并且會從
fork
數組中選擇一個還未使用的
ngx_processes
元素存儲這個子程序的相關資訊。
ngx_process_t