1. 程式人生 > >菜鳥學習nginx之模組定義

菜鳥學習nginx之模組定義

今天開始介紹Nginx框架相關內容。

Nginx將所有功能進行模組化區分,按照功能統一編排,例如:事件模組,HTTP模組,郵箱模組,配置檔案模組等。對於複雜模組,又支援子模組定義,例如HTTP模組中有ngx_http_header_filter_module等。Nginx為這些模組都進行統一的封裝,保證介面的統一化。接下來我們來學習一下Nginx優良設計。

一、Nginx架構

我們先來看一下,Nginx整體框架,可能理解不是清晰,如有不對請大家留言,虛心接受指點。

說明:

  1. Nginx功能強大之一體現在可定製化。Nginx配置檔案非常強大,對於一般需求,只需要修改配置檔案即可滿足。而Nginx中ngx_conf_module模組又是基礎模組。
  2. Nginx定義了一些核心模組(ngx_module_t中type為NGX_CORE_MODULE),我將定義為抽象層。各個抽象層中模組,會定義出具體介面。例如HTTP模組所具有的特徵以及行為。上圖出所有橙色模組都是核心模組。
  3. 實現層主要定義各個模組具體行為,例如http模組報文解析,訪問許可權等。
  4. 由於篇幅問題,在上圖中只畫出事件模組和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事件驅動