nginx的module開發很弱,首先它不是采用動態庫的形式被主進程加載,而是要求module的源碼必須和nginx的源碼一起編譯。我是第一次見到這么BT的家伙,呵呵。所以呢,對module開發者來說,nginx就是一個開發平臺,可以把它理解為在nginx這個“OS”上用C語言開發application,而且要遵循nginx的框架。
既然是平臺,那么像其他OS一樣,我們需要搞明白幾點:1、程序入口和調用方式。2、HTTP處理框架。3、對Http body的處理。4、Upstream機制。5、內存使用。6、配置文件的使用。7、LOG的API。
?
1、先要搞明白程序入口,就像在LINUX上寫可執行程序會自動去找main方法一樣。下面我會用一個例子來說明一下處理流程。
nginx的程序入口先要在module所在目錄的config文件里配置,類似:
~~~
USE_SHA1=YES
ngx_addon_name=ngx_XXX_module
HTTP_MODULES="$HTTP_MODULES ngx_XXX_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_XXX_module.
~~~
同時在module源文件中,定義如下結構:
~~~
static ngx_command_t ngx_XXX_commands[] = {
?{
???ngx_string("XXX"),
???NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
???ngx_XXX_init,
???0,
???0,
???NULL
?}
};
?
static ngx_http_module_t ngx_XXX_module_ctx = {
???NULL, //ngx_XXX_add_variables, ????????/* preconfiguration */
???NULL,????????????????????????????????? /* postconfiguration */
?
???NULL,????????????????????????????????? /* create main configuration */
???NULL,????????????????????????????????? /* init main configuration */
?
???NULL,????????????????????????????????? /* create server configuration */
???NULL,????????????????????????????????? /* merge server configuration */
?
???ngx_XXX_create_loc_conf,?????? /* create location configuration */
???ngx_XXX_merge_loc_conf???????? /* merge location configuration */
};
?
?
ngx_module_t ngx_XXX_module = {
?NGX_MODULE_V1,
?&ngx_XXX_module_ctx,
?ngx_XXX_commands,
?NGX_HTTP_MODULE,
?NULL,
?NULL,
?NULL,
?NULL,
?NULL,
?NULL,
?NULL,
?NGX_MODULE_V1_PADDING
};
~~~
那么,nginx主進程在啟動時,就會在執行代碼里找相應的ngx_module_t(ngx_XXX_module)變量,找到后,在其中ngx_command_t(ngx_XXX_commands)指定的函數ngx_XXX_init里開始初始化模塊。所有的工作都要在這里進行了,包括后續對每個請求的處理訂閱。
Nginx啟動時,會先啟動一個master管理進程,然后根據配置啟動數個worker進程。實際的module里的勾子函數(例如ngx_XXX_handle),都是被worker進程所調用的。默認情況下,nginx并不是多線程的,所以,如果你的勾子函數被調用了,那么你絕對不可以有任何阻塞操作,否則會使得nginx worker不去處理已經在鏈表中的其他connection,這就完全毀了nginx,如果你去同步請求硬盤IO資源,否則其他SERVER的網絡IO,那么它和apach+CGI這種低性能SERVER也沒啥兩樣了,除了epoll可以hold住大量連接。