結合源碼看nginx-1.4.0之nginx模塊組織結構詳解

目錄

0. 摘要nginx

1. nginx模塊組織結構web

2. nginx模塊數據結構後端

3. nginx模塊初始化數組

4. 一個簡單的http模塊服務器

5. 小結網絡

6. 參考資料數據結構

 

0. 摘要

nginx有五大優勢:模塊化、事件驅動、異步、非阻塞、多進程單線程。其中,模塊化設計相似於面向對象中的接口類,它加強了nginx源碼的可讀性、可擴充性和可維護性。負載均衡

nginx-1.4.0總共有5大一類模塊:core、conf、event、http、mail,和48個二類模塊(我本身的安裝版本)。每一個模塊有屬於本身的配置項,由commands字段決定;模塊在初始化和退出銷燬時均有回調函數。多進程模式下的模塊初始化主要有四個方面:腳本初始化、靜態初始化、動態初始化、進程初始化。腳本初始化是指在安裝nginx時,由configure腳本生成的相關文件,好比ngx_modules.c文件包含了nginx的全部模塊;靜態初始化在編譯時就完成,主要經過定義全局變量實現;動態初始化在運行時完成,主要經過master進程main函數,ngx_init_cycle函數,及各模塊文件內定義的init函數實現;進程初始化是指各worker進程執行 init_process函數。當nginx退出或重讀配置文件或nginx平滑升級時,worker進程會調用各模塊的exit_process函數來銷燬資源。異步

開發人員能夠根據nginx模塊規則註冊本身的模塊,添加模塊後要從新編譯源碼,而且修改nginx.conf配置文件才能使新模塊生效。模塊化

1. nginx模塊組織結構

nginx源碼雖然是用c語言寫的,但一點也不妨礙nginx以高度模塊化聞名,這來自於nginx做者對c語言和麪向對象的高度駕馭能力。

1.1 nginx模塊主要輪廓

    Nginx模塊主要有4種角色:
    (1) core(核心模塊):構建nginx基礎服務、管理其餘模塊。
    (2) handlers(處理模塊): 用於處理HTTP請求,而後產生輸出。
    (3) filters(過濾模塊): 過濾handler產生的輸出。
    (4) load-balancers(負載均衡模塊):當有多於一臺的後端備選服務器時,選擇一臺轉發HTTP請求。
    Nginx的核心模塊主要負責創建nginx服務模型、管理網絡層和應用層協議、以及啓動針對特定應用的一系列候選模塊。其餘模塊負責分配給web服務器的實際工做:當Nginx發送文件或者轉發請求到其餘服務器,由處理模塊或負載均衡模塊提供服務;當須要Nginx把輸出壓縮或者在服務端加一些東西,由過濾模塊提供服務。
    那麼模塊是如何被調用的?當服務器啓動,每一個處理模塊都有機會映射到配置文件中定義的特定位置(location);若是有多個處理模塊映射到特定位置時,只有一個會「贏」(說明配置文件有衝突項,應該避免發生)。處理模塊以三種形式返回:OK、ERROR、或者放棄處理這個請求而讓默認處理模塊來處理(主要是用來處理一些靜態文件,事實上若是是位置正確而真實的靜態文件,默認的處理模塊會搶先處理)。
    若是處理模塊把請求反向代理到後端的服務器,就變成另一類的模塊:負載均衡模塊。負載均衡模塊的配置中有一組後端服務器,當一個HTTP請求過來時,它決定哪臺服務器應當得到這個請求。Nginx的負載均衡模塊採用兩種方法:輪轉法,它處理請求就像紙牌遊戲同樣從頭至尾分發;IP哈希法,在衆多請求的狀況下,它確保來自同一個IP的請求會分發到相同的後端服務器。
    若是處理模塊沒有產生錯誤,過濾模塊將被調用。多個過濾模塊能映射到每一個位置,因此(好比)每一個請求均可以被壓縮成塊。它們的執行順序在編譯時決定。過濾模塊是經典的「接力鏈表(CHAIN OF RESPONSIBILITY)」模型:一個過濾模塊被調用,完成其工做,而後調用下一個過濾模塊,直到最後一個過濾模塊。Nginx完成這個回覆。過濾模塊鏈的特別之處在於,每一個過濾模塊不會等上一個過濾模塊所有完成;它能把前一個過濾模塊的輸出做爲其處理內容;有點像Unix中的流水線。過濾模塊能以buffer(緩衝區)爲單位進行操做,這些buffer通常都是一頁(4K)大小,固然你也能夠在nginx.conf文件中進行配置。這意味着,好比,模塊能夠壓縮來自後端服務器的回覆,而後像流同樣的到達客戶端,直到整個回覆發送完成。總之,過濾模塊鏈以流水線的方式高效率地向客戶端發送響應信息。
    因此總結下上面的內容,一個典型的處理週期是這樣的:
    客戶端發送HTTP請求->Nginx基於配置文件中的位置選擇一個合適的處理模塊->(若是有)負載均衡模塊選擇一臺後端服務器->處理模塊進行處理並把輸出緩衝放到第一個過濾模塊上->第一個過濾模塊處理後輸出給第二個過濾模塊->而後第二個過濾模塊又到第三個->依此類推->最後把回覆發給客戶端。
    圖1.1展現了nginx模塊處理流程。

圖1.1 nginx模塊處理流程圖

1.2 nginx模塊結構設計

圖1.2 nginx 模塊結構設計圖

 

圖1.3 nginx主要模塊組織結構簡圖

2. nginx模塊數據結構

2.1 模塊主要數據結構 

(1)核心:ngx_module_t(nginx全部模塊的數據結構模板)

 1 #define NGX_MODULE_V1          0, 0, 0, 0, 0, 0, 1 // 初始化 ngx_module_s 前7個字段
 2 #define NGX_MODULE_V1_PADDING  0, 0, 0, 0, 0, 0, 0, 0 // 初始化 ngx_module_s 最後8個字段
 3 typedef struct ngx_module_s      ngx_module_t;
 4 struct ngx_module_s {
 5     ngx_uint_t            ctx_index; // ctx:context 分類模塊索引,好比http類型模塊有不少實例
 6     ngx_uint_t            index; // 全局模塊索引,在nginx.c中main函數體內進行動態初始化
 7 
 8     ngx_uint_t            spare0;  // 目前未使用
 9     ngx_uint_t            spare1;  // 目前未使用
10     ngx_uint_t            spare2;  // 目前未使用
11     ngx_uint_t            spare3;  // 目前未使用
12 
13     ngx_uint_t            version; // 模塊版本
14 
15     void                 *ctx; // 該模塊的上下文,通常用來建立和初始化模塊配置數據結構,每一個種類的模塊有不一樣的上下文
16     ngx_command_t        *commands;// 該模塊對應的配置文件中的語句塊,指向一個ngx_command_t結構數組
17     ngx_uint_t            type;// 該模塊的種類,爲core/conf/event/http/mail中的一種
18     // 如下是一些callback函數
19     ngx_int_t           (*init_master)(ngx_log_t *log); // 初始化master: 目前未使用
20 
21     ngx_int_t           (*init_module)(ngx_cycle_t *cycle);// 初始化模塊
22 
23     ngx_int_t           (*init_process)(ngx_cycle_t *cycle); // 初始化工做進程
24     ngx_int_t           (*init_thread)(ngx_cycle_t *cycle); // 初始化線程:目前未使用
25     void                (*exit_thread)(ngx_cycle_t *cycle); // 退出線程:目前未使用
26     void                (*exit_process)(ngx_cycle_t *cycle); // 退出工做進程
27 
28     void                (*exit_master)(ngx_cycle_t *cycle); // 退出master:目前未使用
29     // 這些字段:目前未使用
30     uintptr_t             spare_hook0;
31     uintptr_t             spare_hook1;
32     uintptr_t             spare_hook2;
33     uintptr_t             spare_hook3;
34     uintptr_t             spare_hook4;
35     uintptr_t             spare_hook5;
36     uintptr_t             spare_hook6;
37     uintptr_t             spare_hook7;
38 };

(2) 配置文件指令:ngx_command_t(主要負責模塊與配置文件nginx.conf的交互)

 1 typedef struct ngx_command_s     ngx_command_t;
 2 #define NGX_CONF_NOARGS      0x00000001
 3 #define NGX_CONF_TAKE1       0x00000002
 4 #define NGX_CONF_TAKE2       0x00000004
 5 #define NGX_CONF_TAKE3       0x00000008
 6 #define NGX_CONF_TAKE4       0x00000010
 7 #define NGX_CONF_TAKE5       0x00000020
 8 #define NGX_CONF_TAKE6       0x00000040
 9 #define NGX_CONF_TAKE7       0x00000080
10 
11 #define NGX_CONF_MAX_ARGS    8
12 
13 #define NGX_CONF_TAKE12      (NGX_CONF_TAKE1|NGX_CONF_TAKE2)
14 #define NGX_CONF_TAKE13      (NGX_CONF_TAKE1|NGX_CONF_TAKE3)
15 
16 #define NGX_CONF_TAKE23      (NGX_CONF_TAKE2|NGX_CONF_TAKE3)
17 
18 #define NGX_CONF_TAKE123     (NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3)
19 #define NGX_CONF_TAKE1234    (NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3   \
20                               |NGX_CONF_TAKE4)
21 
22 #define NGX_CONF_ARGS_NUMBER 0x000000ff
23 #define NGX_CONF_BLOCK       0x00000100
24 #define NGX_CONF_FLAG        0x00000200
25 #define NGX_CONF_ANY         0x00000400
26 #define NGX_CONF_1MORE       0x00000800
27 #define NGX_CONF_2MORE       0x00001000
28 #define NGX_CONF_MULTI       0x00000000  /* compatibility */
29 
30 #define NGX_DIRECT_CONF      0x00010000
31 
32 #define NGX_MAIN_CONF        0x01000000
33 #define NGX_ANY_CONF         0x0F000000
34 
35 
36 
37 #define NGX_CONF_UNSET       -1
38 #define NGX_CONF_UNSET_UINT  (ngx_uint_t) -1
39 #define NGX_CONF_UNSET_PTR   (void *) -1
40 #define NGX_CONF_UNSET_SIZE  (size_t) -1
41 #define NGX_CONF_UNSET_MSEC  (ngx_msec_t) -1
42 
43 
44 #define NGX_CONF_OK          NULL
45 #define NGX_CONF_ERROR       (void *) -1
46 
47 #define NGX_CONF_BLOCK_START 1
48 #define NGX_CONF_BLOCK_DONE  2
49 #define NGX_CONF_FILE_DONE   3
50 
51 // 模塊種類宏,定義爲一個十六進制的數,這個十六進制的數就是其類型對應的ASCII碼。
52 // 所以,nginx共有5種類型的模塊,分別爲"CORE","CONF","EVNT","HTTP","MAIL"。
53 #define NGX_CORE_MODULE      0x45524F43  /* "CORE" */
54 #define NGX_CONF_MODULE      0x464E4F43  /* "CONF" */
55 
56 
57 #define NGX_MAX_CONF_ERRSTR  1024
58 
59 
60 struct ngx_command_s {
61     ngx_str_t             name; // 配置文件中的指令,如 daemon
62     // 指令出現的位置(main/http/server/location/upstream/mail)
63     // 指令值的數據類型,如NGX_CONF_FLAG表示指令讀入一個布爾型數據
64     // 指令後帶的參數,如NGX_CONF_TAKE1表示帶一個參數
65     ngx_uint_t            type; 
66     char               *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); // 設置指令值到模塊自定義數據結構
67     ngx_uint_t            conf; // 通常爲 0
68     ngx_uint_t            offset; // 指令在數據結構的偏移量
69     void                 *post;  // 通常爲 NULL
70 };
71 
72 #define ngx_null_command  { ngx_null_string, 0, NULL, 0, 0, NULL }

(3)指令配置:ngx_conf_t(解析某個具體的指令)

 1 typedef char *(*ngx_conf_handler_pt)(ngx_conf_t *cf, ngx_command_t *dummy, void *conf);
 2 typedef struct ngx_conf_s        ngx_conf_t;
 3 struct ngx_conf_s {
 4     char                 *name;         // 指令名
 5     ngx_array_t          *args;         // 指令後的參數
 6 
 7     ngx_cycle_t          *cycle;        // 全局數據結構
 8     ngx_pool_t           *pool;         // 內存池
 9     ngx_pool_t           *temp_pool;    // 臨時內存池
10     ngx_conf_file_t      *conf_file;    // 指令所在配置文件
11     ngx_log_t            *log;          // 日誌記錄
12 
13     void                 *ctx;          // 模塊上下文
14     ngx_uint_t            module_type;  // 模塊類型
15     ngx_uint_t            cmd_type;     // 指令類型
16 
17     ngx_conf_handler_pt   handler;      // set函數指針
18     char                 *handler_conf; // set函數返回值
19 };

 (4)全局配置:ngx_cycle_t(nginx絕大部分初始化操做都圍繞該結構體)

 1 typedef struct ngx_cycle_s       ngx_cycle_t;
 2 struct ngx_cycle_s {
 3     void                  ****conf_ctx;                       // 配置上下文數組(含全部模塊)
 4     ngx_pool_t               *pool;                           // 內存池
 5 
 6     ngx_log_t                *log;                            // 日誌
 7     ngx_log_t                 new_log;
 8 
 9     ngx_connection_t        **files;                         // 鏈接文件
10     ngx_connection_t         *free_connections;              // 空閒鏈接
11     ngx_uint_t                free_connection_n;             // 空閒鏈接個數
12 
13     ngx_queue_t               reusable_connections_queue;    // 再利用鏈接隊列
14 
15     ngx_array_t               listening;                     // 監聽套接字數組
16     ngx_array_t               pathes;                        // 路徑數組
17     ngx_list_t                open_files;                    // 打開文件鏈表
18     ngx_list_t                shared_memory;                 // 共享內存鏈表
19 
20     ngx_uint_t                connection_n;                  // 鏈接個數
21     ngx_uint_t                files_n;                       // 打開文件個數
22 
23     ngx_connection_t         *connections;                   // 鏈接
24     ngx_event_t              *read_events;                   // 讀事件
25     ngx_event_t              *write_events;                  // 寫事件
26 
27     ngx_cycle_t              *old_cycle;                     // old cycle指針
28 
29     ngx_str_t                 conf_file;                     // 配置文件
30     ngx_str_t                 conf_param;                    // 配置參數
31     ngx_str_t                 conf_prefix;                   // 配置文件目錄
32     ngx_str_t                 prefix;                        // 程序工做目錄
33     ngx_str_t                 lock_file;                     // 鎖文件,用在不支持accept_mutex的系統中
34     ngx_str_t                 hostname;                      // 主機名
35 };

2.2 模塊數據結構相關操做

(1)指令設置回調函數:*(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);

    結構體成員set是一個函數指針,用來設定模塊的配置;典型地,這個函數會轉化指令傳進來的參數,而後將合適的值保存到配置結構體。這個設定函數有三個參數:
    1)指向ngx_conf_t結構體的指針,包含從指令後面傳過來的參數。
    2)指向當前ngx_command_t結構體的指針
    3)指向自定義模塊配置結構體的指針
    這個設定函數在指令被遇到的時候就會調用。在自定義的配置結構體中,Nginx提供了多個函數用來保存特定類型的數據,這些函數包含有:
    1)ngx_conf_set_flag_slot: 將」on」或」off」轉化爲布爾類型
    2)ngx_conf_set_str_slot: 將字符串保存爲ngx_str_t類型
    3)ngx_conf_set_num_slot: 解析一個數字並保存爲int型
    4)ngx_conf_set_size_slot: 解析一個數據大小(如:」8k」, 「1m」) 並保存爲 size_t類型
    還有另一些,很容易查到(看,core/ngx_conf_file.h)。模塊也能夠把它們本身函數的引用放在這裏,但這樣內嵌的類型不是很好。
那這些內嵌函數怎麼知道要把值保存在哪裏呢?ngx_command_t接下來的兩個成員conf和offset正好可用。conf告訴Nginx把這個值是放在全局配置部分、主機配置部分仍是位置配置部分呢(用NGX_HTTP_MAIN_CONF_OFFSET, NGX_HTTP_SRV_CONF_OFFSET或NGX_HTTP_LOC_CONF_OFFSET)。而後offset肯定究竟是保存在結構體的哪一個位置。
    最後,post指向模塊在讀配置的時候須要的一些零碎變量。通常它是NULL。
    這個ngx_command_t數組在讀入ngx_null_command 後中止,也即最後一個成員。

3. nginx模塊初始化

3.1 腳本初始化

3.2 靜態初始化

3.3 動態初始化

3.4 進程初始化

4. 一個簡單的http模塊

4.1 註冊模塊

4.2 實現簡單的http模塊

5. 小結

6. 參考資料

相關文章
相關標籤/搜索