菜鳥學習nginx之模組定義
今天開始介紹Nginx框架相關內容。
Nginx將所有功能進行模組化區分,按照功能統一編排,例如:事件模組,HTTP模組,郵箱模組,配置檔案模組等。對於複雜模組,又支援子模組定義,例如HTTP模組中有ngx_http_header_filter_module等。Nginx為這些模組都進行統一的封裝,保證介面的統一化。接下來我們來學習一下Nginx優良設計。
一、Nginx架構
我們先來看一下,Nginx整體框架,可能理解不是清晰,如有不對請大家留言,虛心接受指點。
說明:
- Nginx功能強大之一體現在可定製化。Nginx配置檔案非常強大,對於一般需求,只需要修改配置檔案即可滿足。而Nginx中ngx_conf_module模組又是基礎模組。
- Nginx定義了一些核心模組(ngx_module_t中type為NGX_CORE_MODULE),我將定義為抽象層。各個抽象層中模組,會定義出具體介面。例如HTTP模組所具有的特徵以及行為。上圖出所有橙色模組都是核心模組。
- 實現層主要定義各個模組具體行為,例如http模組報文解析,訪問許可權等。
- 由於篇幅問題,在上圖中只畫出事件模組和http模組
這裡可以用一個形象的比喻來描述Nginx框架:綠色相當於學校的場地,教學樓等屬於基礎設施,橙色相當於校長,教導主任等上層管理者,藍色相當於班主任,負責每個班級的管理,紫色相當於學生。
二、模組定義
Nginx中萬物皆模組,當我們為了新的業務需求時需要定製開發,我們必須定義成一個module。下面是Nginx中module結構體定義,如下:
struct ngx_module_s { /** * 每個模組又可以存在子模組,例如: ngx_event_core_module, ngx_epoll_module * 都是從屬於ngx_events_module模組的子模組。 * ctx_index初始化在函式ngx_count_modules中 */ ngx_uint_t ctx_index; /** * 陣列下標 在configure過程中生成檔案ngx_modules.c 裡面有一個數組ngx_modules * 其index就是ngx_modules陣列下標. index初始化ngx_module_index */ ngx_uint_t index; char *name; //模組名稱 ngx_uint_t spare0; ngx_uint_t spare1; ngx_uint_t version; const char *signature; /** 模組定義時指定 * 不同模組實際指向不同,例如: * NGX_CORE_MODULE 指向的結構體ngx_core_module_t * NGX_EVENT_MODULE 指向的結構體ngx_event_module_t * NGX_HTTP_MODULE 指向的結構體ngx_http_module_t */ void *ctx; ngx_command_t *commands; // 配置檔案解析對映表 ngx_uint_t type; // 指定模組型別 ngx_int_t (*init_master)(ngx_log_t *log);//目前沒有使用 ngx_int_t (*init_module)(ngx_cycle_t *cycle);//ngx_init_cycle中呼叫 ngx_int_t (*init_process)(ngx_cycle_t *cycle); ngx_int_t (*init_thread)(ngx_cycle_t *cycle); void (*exit_thread)(ngx_cycle_t *cycle); void (*exit_process)(ngx_cycle_t *cycle); void (*exit_master)(ngx_cycle_t *cycle); 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; };
欄位名稱 |
含義 |
備註 |
ctx_index |
當前module在子型別下索引值 |
Nginx支援子型別。例如Nginx定義了很多NGX_HTTP_MODULE (http模組),那麼這些module需要指定在HTTP模組下面索引,就是用ctx_index表示。 |
index |
當前module在全域性陣列ngx_modules下標 |
Module在全域性陣列ngx_modules中下標值 |
name |
模組名稱 |
|
spare0 ~ spare1 |
預留 |
|
version |
版本號 |
|
signature |
簽名 |
|
ctx |
當前模組上下文 |
模組在定義時需要指定ctx值,相同模組型別,指向的上下文是相同的。 |
commands |
配置檔案解析 |
用於解析配置檔案,例如出現某個標籤,需要呼叫對應的解析函式。該變數在模組定義時指定 |
type |
當前模組型別 |
|
init_master |
沒有使用 |
|
init_module |
初始化模組 |
在函式ngx_init_cycle中呼叫 |
init_process |
模組定義的worker程序初始化 |
在函式ngx_worker_process_init中呼叫 |
init_thread |
沒有使用 |
|
exit_thread |
沒有使用 |
|
exit_process |
程序退出 |
在函式ngx_worker_process_exit中呼叫 |
exit_master |
master程序退出 |
在函式ngx_master_process_exit中呼叫 |
spare_hook0 ~spare_hook1 |
預留 |
|
說明:
目前Nginx內建模組型別(type)有:NGX_CONF_MODULE,NGX_CORE_MODULE,NGX_EVENT_MODULE,NGX_HTTP_MODULE,NGX_MAIL_MODULE,NGX_STREAM_MODULE
下面以ngx_events_module舉例說明,以此來感知定義方式:
/**
* 解析命令字 即解析配置檔案 當配置檔案出現標籤events時呼叫ngx_events_block方法
*/
static ngx_command_t ngx_events_commands[] = {
{ngx_string("events"),
NGX_MAIN_CONF | NGX_CONF_BLOCK | NGX_CONF_NOARGS,
ngx_events_block,
0,
0,
NULL},
ngx_null_command};
/**
* 定義模組上下文,當我們新增核心模組時,需要指定ngx_core_module_t作為上下文
*/
static ngx_core_module_t ngx_events_module_ctx = {
ngx_string("events"),
NULL,
ngx_event_init_conf};
/**
* 模組定義--事件模組
*/
ngx_module_t ngx_events_module = {
NGX_MODULE_V1,
&ngx_events_module_ctx, /* module context 模組上下 ctx*/
ngx_events_commands, /* module directives */
NGX_CORE_MODULE, /* module type 事件模組作為核心模組 */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
三、模組初始化
在介紹啟動流程時,已經比較詳細介紹過關於模組的初始化。簡單回顧一下。
首先,Nginx將所有模組都統一到ngx_modules陣列中,該陣列是在configure過程中生成,陣列定義在ngx_modules.c檔案中,如下:
ngx_module_t *ngx_modules[] = {
&ngx_core_module,
&ngx_errlog_module,
&ngx_conf_module,
&ngx_regex_module,
&ngx_events_module,
&ngx_event_core_module,
&ngx_epoll_module,
&ngx_http_module,
&ngx_http_core_module,
...
}
其中ngx_module_t結構體中index就是該陣列下標。Nginx在管理模組索引時採用的就是陣列下標,所以我們不能輕易修改下標值。
ctx_index所以也是基於下標,但是下標不是和index一樣。先劃分模組型別(type)進行類別分類,最後在統一編排。
/**
* 獲取相同型別下module數量
* @param cycle 核心結構體
* @param type 模組型別 例如NGX_EVENT_MODULE,NGX_HTTP_MODULE
* @return 返回數量
* 注意此方法,還會設定子型別索引 即在相同module型別下ctx_index
*/
ngx_int_t
ngx_count_modules(ngx_cycle_t *cycle, ngx_uint_t type)
其次,呼叫init_module回撥函式,用於初始化模組。例如核心模組ngx_event_core_module中ngx_event_module_init,初始化共享記憶體等。
再次,在worker程序建立之後呼叫init_process回撥函式,初始化服務相關。例如:監聽埠新增到事件驅動中。
對於事件模組後續有專題介紹
四、總結
本篇主要介紹的內容是,如何定義一個module以及module中重要成員。因為Nginx中所有功能模組都是module進行劃分,如果對於module使用以及定義仍然不清楚的,可參考我之前寫的《菜鳥學習Nginx之入門開發留言板》,下一篇介紹Nginx事件驅動。