nginx架構總結--nginx原始碼系列(一)
總述:
nginx自身是高度模組化設計的,我們可以方便的開發任何基於tcp的模組(比如http模組,mail模組)。
注: 一、開發一個nginx模組,必須遵守的原則有:1、實現模組開發的介面 2、不能有阻塞的系統呼叫
二、web伺服器提高網路效率的方法有:1、使用長連線(keepalive)代替短連線,減少建立、關閉連線帶來的開銷
2、使用壓縮演算法來增加相同吞吐量下的資訊攜帶量;3、使用快取來減少網路互動次數
nginx總結起來就是一個框架和五類模組
一、nginx的模組化設計
nginx的框架程式碼只佔少部分,主要負責建立程序模型並使各個模組有序的執行,當然還包括一系列資源初始化和回收(從某種意義上來說,nginx自定義的資料結構和對系統呼叫的封裝也可以視為框架程式碼)。
所有的模組都遵循著同樣的ngx_module_t介面設計規範
//ngx_module_s是模組的定義
struct ngx_module_s {
//對於一類模組(由下面的type成員決定類別)而言,ctx_index標示當前模組在這類模組中的序號。
//這個成員常常是由管理這類模組的一個nginx核心模組設定的,對於所有的HTTP模組而言,ctx_index
//是由核心模組ngx_http_module設定的。
ngx_uint_t ctx_index;
//index表示當前模組在ngx_modules陣列中的序號。Nginx啟動的時候會根據ngx_modules陣列設定各個模組的index值
ngx_uint_t index;
//spare系列的保留變數,暫未使用
ngx_uint_t spare0;
ngx_uint_t spare1;
ngx_uint_t spare2;
ngx_uint_t spare3;
//nginx模組版本,目前只有一種,暫定為1
ngx_uint_t version;
//模組上下文,每個模組有不同模組上下文,每個模組都有自己的特性,而ctx會指向特定型別模組的公共介面。
//比如,在HTTP模組中,ctx需要指向ngx_http_module_t結構體。
void *ctx;
//模組命令集,將處理nginx.conf中的配置項
ngx_command_t *commands;
//標示該模組的型別,和ctx是緊密相關的。它的取值範圍是以下幾種:
//NGX_HTTP_MODULE,NGX_CORE_MODULE,NGX_CONF_MODULE,
//NGX_EVENT_MODULE,NGX_MAIL_MODULE
ngx_uint_t type;
//下面7個函式是nginx在啟動,停止過程中的7個執行點
ngx_int_t (*init_master)(ngx_log_t *log); //初始化master
ngx_int_t (*init_module)(ngx_cycle_t *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); //退出master
//保留欄位,無用,可以使用NGX_MODULE_V1_PADDING來替換
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;
};
基本介面ngx_module_t只涉及模組的初始化、退出以及對配置項的處理。如上程式碼所示,ngx_module_t結構體作為所有模組的通用介面,只定義了init_master 、init_module、init_process、init_thread、exit_thread、exit_process、exit_master這七個回撥方法,而init_master 、init_thread、exit_thread這三個方法目前沒有使用,後兩個是因為nginx目前沒有使用執行緒(因為多執行緒程式碼實現更難控制)。他們負責模組的初始化和退出,同時他們可以處理核心結構體ngx_cycle_t(每個程序都有一個該結構體變數)。而ngx_command_t型別的commands陣列指定了模組中的配置名和模組處理配置變數的方法,ctx是一個void*指標,他表示一類模組所特有的通用函式介面。
上圖包括核心、事件、http、mail四類模組的ctx上下文(配置模組的ctx上下文為空),和ngx_command_t結構。
配置模組是唯一一種只有一個模組的模組型別,這是nginx最底層的模組,他指導著所有模組以配置項為核心來提供功能。因此,他是所有其他模組的基礎(但是,單就conf模組對ngx_module_t介面的實現情況來說,他只是實現了include命令,以及程序退出時執行的一個回撥方法)。
核心型別的模組一共只有六個:ngx_core_module、ngx_errlog、ngx_events_module、ngx_openssl_module、ngx_http_module、ngx_mail_module。非模組的框架程式碼只關注於如何呼叫六個核心模組(大部分nginx模組都是非核心模組)。
typedef struct {
ngx_str_t name; //模組名,即ngx_core_module_ctx結構體物件的
void *(*create_conf)(ngx_cycle_t *cycle); //解析配置項前,nginx框架會呼叫create_conf方法
char *(*init_conf)(ngx_cycle_t *cycle, void *conf); //解析配置項完成後,nginx框架會呼叫init_conf方法
} ngx_core_module_t;
ngx_core_module_t上下文是以配置項的解析作為基礎的,它提供了create_conf回撥方法來建立儲存配置項的資料結構,在讀取nginx.conf配置檔案時,會根據模組中的ngx_command_t把解析出的配置項存放在這個資料結構中;他還提供了init_conf回撥方法,用於在解析完配置檔案後,使用解析出的配置項初始化模組功能。(但是,很多核心模組,比如http,event,mail並沒有實現這個介面,而是在解析配置的時候,比如解析http命令時,呼叫命令處理函式來建立資料結構和初始化模組功能,http還會在回撥函式裡建立http模組型別的上下文以及初始化http類的那些模組中的一些屬性)。
配置模組和核心模組這兩類模組是由nginx的框架程式碼所定義的,這裡的配置模組是所有模組的基礎,他實現了最基本的配置項解析功能(就是解析nginx.conf檔案)。其他三類模組都不會與框架產生直接關係。事件,http,mail這三類模組,都在核心模組中各有一個模組作為自己的”代言人“,並在同類模組中還有一個作為核心業務與管理功能的模組。
注:每個ngx_listening_t都有一個ngx_connection_t與之對應,反過來則不然。這樣是為了使監聽套接字操作起來和 連線套接字一樣。完全是為了使監聽套接字上的事件(只有可讀事件)處理和連線套接字統一。