高度模塊化的設計是nginx的架構基礎。在nginx中,除了少許的核心代碼,其餘一切皆爲模塊。這種模塊化設計同時具備如下幾個特色:nginx
全部的模塊都遵循着一樣的 ngx_module_t 接口設計規範,這減小了整個系統中的變數。數組
模塊的基本接口 ngx_module_t 足夠簡單,只涉及模塊的初始化、退出以及對配置項的處理、這同時也帶來了足夠的靈活性,使得nginx比較簡單地實現了動態可修改性。多線程
ngx_module_t接口有一個type成員,它指明瞭nginx容許在設計模塊時定義模塊類型這個概念,容許專一於不一樣領域的模塊按照類型來區別。而配置類型模塊是惟一一種只有1個模塊的模塊類型。配置模塊的類型叫作NGX_CONF_MODULE,它僅有的模塊叫作ngx_conf_module。這是nginx最底層的模塊,它指導着全部模塊以配置項爲核心來提供功能。所以,它是其餘全部模塊的基礎。配置模塊使nginx提供了高可配置性,高可擴展性,高可定製性,高可伸縮性。架構
nginx中定義了一種基礎類型的模塊——核心模塊。核心模塊的存在簡化了nginx的設計,使得非模塊化的框架代碼只關注於如何調用這些核心模塊。框架
全部的模塊間是分層次的,分類別的。不一樣的模塊雖然都具有相同的ngx_module_t接口,單在請求處理流程中的層次並不相同。nginx將各功能組織成一條鏈,當有請求到達的時候,請求依次通過這條鏈上的部分或者所有模塊進行處理。模塊化
nginx模塊分爲核心模塊和功能性模塊,功能性模塊包括conf、event、http、mail、stream幾大類。除了conf類之外,其餘幾類功能性模塊都包含衆多的模塊,而且每一個類別中都有一個核心模塊。其主要做用是提供本類別功能通用的框架接口,邏輯處理等,並調用同類型的其餘模塊完成具體的功能。例如NGX_HTTP_MODULE類別中的核心模塊ngx_http_core_module,負責http塊配置項中通用的配置解析、http請求處理的總體流程,並調用其餘NGX_HTTP_MODULE模塊完成具體的處理。函數
nginx中經常使用模塊分層分類:post
struct ngx_module_s { ngx_uint_t ctx_index; // 模塊在同類型模塊數組中的索引序號 ngx_uint_t index; // 模塊在全部模塊數組中的索引序號 char * name; // 模塊的名稱 ngx_uint_t spare0; // 保留變量 ngx_uint_t spare1; // 保留變量 ngx_uint_t version; // 模塊的版本號 目前只有一種,默認爲1 const char* signature; void * ctx; // 模塊上下文結構體 不一樣的模塊指向不一樣的結構體 ngx_command_t * commands; // 模塊關心的配置項表 配置文件解析時會查找該表 ngx_uint_t type; // 模塊類型 如NGX_CORE_MODULE ngx_int_t (*init_master)(ngx_log_t *log); // master進程啓動時回調 ngx_int_t (*init_module)(ngx_cycle *cycle); // 初始化模塊時回調 ngx_int_t (*init_process)(ngx_cycle_t *cycle); // worker進程啓動時回調 ngx_int_t (*init_thread)(ngx_cycle_t *cycle); // 線程啓動時回調(nginx暫時無多線程模式) void (*exit_thread)(ngx_cycle_t *cycle); // 線程退出時回調 void (*exit_process)(ngx_cycle_t *cycle); // worker進程退出時回調 void (*exit_master)(ngx_cycle_t *cycle); // master進程退出時回調 uintptr_t spare_hook0; // 保留字段 uintptr_t spare_hook1; uintptr_t spare_hook2; uintptr_t spare_hook3; uintptr_t spare_hook4; uintptr_t spare_hook5; uintptr_t spare_hook6; uintptr_t spare_hook7; }; typedef struct ngx_module_s ngx_module_t;
struct ngx_command_s { // 配置項的名稱 ngx_str_t name; // 配置項的類型 ngx_uint_t type; // 配置項解析處理函數 char * (*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); // 用於指示配置項所處內存的相對偏移位置 ngx_uint_t conf; // 表示當前配置項在整個存儲配置項的結構體中的偏移位置 ngx_uint_t offset; // 配置項讀取後的處理方法 必須是ngx_conf_post_t結構體的指針 void * post; }; typedef struct ngx_command_s ngx_command_t;
typedef struct { // 模塊的名稱 例如 core, http, mail ngx_str_t name; // 分配內存(建立相關結構體)用於存儲配置項解析時配置項值的存儲 void * (*create_conf)(ngx_cycle_t *cycle); // 初始化配置項的初始值 char * (*init_conf)(ngx_cycle_t *cycle, void *conf); } ngx_core_module_t ;
執行configure後,會在objs目錄下生成nginx_modules.c源文件。這個源文件中有兩個很重要的全局變量ngx_modules和ngx_module_names,前者保存了nginx將要使用的所有模塊,後者則記錄了這些模塊的名稱。ui
ngx_module_t *ngx_modules[] = { &ngx_core_module, &ngx_errlog_module, &ngx_conf_module, &ngx_openssl_module, &ngx_regex_module, &ngx_events_module, &ngx_event_core_module, ... }; char *ngx_module_names[] = { "ngx_core_module" "ngx_errlog_module", "ngx_conf_module", "ngx_openssl_module", "ngx_regex_module", "ngx_events_module", "ngx_event_core_module", ... };
初始化每一個模塊的索引以及名稱。spa
ngx_int_t ngx_preinit_modules(void) { ngx_uint_t i; for( i = 0; ngx_modules[i]; i++ ) { ngx_modules[i]->index = i; ngx_modules[i]->name = ngx_module_names[i]; } ngx_modules_n = i; ngx_max_module = ngx_modules_n + NGX_MAX_DYNAMIC_MODULES; return NGX_OK; }
ngx_cycle_t * ngx_init_cycle(ngx_cycle_t *old_cycle) { ... for( i = 0; cycle->modules[i]; i++ ) { if( cycle->modules[i]->type != NGX_CORE_MODULE ) { continue; } module = cycle->modules[i]->ctx; if(module->create_conf) { rv = module->create_conf(cycle); if( rv == NULL ) { ngx_destroy_pool(pool); return NULL; } cycle->conf_ctx[cycle->modules[i]->index] = rv; } } ... }
ngx_cycle_t * ngx_init_cycle(ngx_cycle_t *old_cycle) { ... for( i = 0; cycle->modules[i]; i++ ) { if( cycle->modules[i]->type != NGX_CORE_MODULE ) { continue; } module = cycle->modules[i]->ctx; if(module->init_conf) { if( module->init_conf(cycle, cycle->conf_ctx[cycle->modules[i]->index]) == NGX_CONF_ERROR ) { environ = senv; ngx_destroy_cycle_pools(&conf); return NULL; } } } ... }
ngx_int_t ngx_init_modules(ngx_cycle_t * cycle) { ngx_uint_t i; // 目前只有三個模塊該函數指針非空 // 分別是 event_core, http_v2, regex for( i = 0; cycle->modules[i]; i++ ) { if(cycle->modules[i]->init_module) { if(cycle->modules[i]->init_module(cycle) != NGX_OK) { return NGX_ERROR; } } } return NGX_OK; }
// init_master 回調函數當前沒有使用 即每一個模塊都設置爲NULL // init_process 回調函數當前有event_core, http_userid_filter, thread_pool模塊進行設置 for( i = 0 ; cycle->modules[i]; i++ ) { if( cycle->modules[i]->init_process ) { if( cycle->modules[i]->init_process(cycle) == NGX_ERROR ) { exit(2); } } }
到此模塊初始化流程結束,master/worker進程開始各自的循環。
參考:
《深刻理解nginx》
《nginx開發從入門到精通》