nginx代碼分析之 轉載
導讀:
nginx代碼分析之(一)——初探
不知道原創,作者聯繫下我吧。
他的代碼我全看過了,感覺是高層模型下做的最優精簡指令。效果還是不錯的。
發現nginx是無意間在瀏覽器中看到新浪的一個錯誤頁面“nginx ...”,不由起了好奇心,google了一把,發現這是一個支持負載均衡的反向代理服務器,俄羅斯人開發的,雖然沒有走GNU或BSD的License,但是也算是一個開源軟件。
開源代理服務器最熟悉的還是Squid和Apache,但這兩者都是正反向代理通吃的,而作爲反向代理,實際上和正向代理有較大的差別。我想既然新浪也用它,那自然有它的獨到之處。查了一下,中文的網頁上說它的HTTP性能可以達到13000TPS以上,但是沒有說明數據的出處,國外的網站上暫時找不到相應的數據,但很多人拿它和lighttpd相比。
很快下載了nginx 0.5.32版本的代碼,代碼不多,才8萬多行,在openssl的基礎上支持HTTPS。和Apache的30多萬行相比,精簡了很多,
作爲web server或反向代理,要的就是一個快,要做到快,除了精簡的代碼之外,更關鍵的一點就是併發模型。
Apache的弱點就在於它的併發模型是普通的進程/線程池,連接數和進程/線程數是1:1的,因此無論是prefork還是worker模式,都將每一個連接對應到一個獨立的進程/線程。
這樣的併發模型在連接數不太多(1000以內)時還算可以,但在大規模併發時,其進程/線程總數會非常多。由於Apache本身也比較吃內存,所以到了1000以上的併發時,服務器的內存基本上也就被吃的差不多了,操作系統也在頻繁地做進程/線程的切換,非常吃力。
相比之下,更高級的大型網絡服務系統(如電信的智能網系統)一般採用進程/線程池+狀態機的模型——也即接數和進程/線程數是m:n的,這樣進程/線程總數就不會由於連接的增多而增多,避免了內存和調度切換的開銷,但這種做法對程序邏輯的要求較高,需要一個連接拆分爲多個邏輯狀態(創建,讀,寫,關閉等,根據實際業務還可以更加細化)每個進程/線程處理完某一種狀態後,需要改變該連接的狀態值,後續狀態由下一個空閒的進程/線程處理。
nginx就採用了這樣的併發模型,對於連接狀態的存儲,nginx主要採用了這樣一個複雜結構。
struct ngx_connection_s {
void *data;
ngx_event_t *read;
ngx_event_t *write;
...
};
結構ngx_event_t存儲了連接IO狀態的詳細信息,同時所有的ngx_event_t組成了兩個全局的鏈表,以便進行存取操作。
在這兩個數據結構的基礎上,nginx使用了下面這兩個函數來完成每個進程/線程的循環
1. ngx_locked_post_event
這個函數負責更新某一個連接的狀態,在檢查到連接IO狀態改變(比如通過select)後被調用。
nginx以module的方式提供了select語義的多種實現:
poll
devpoll
epoll
eventport
kqueue
rtsig
後面4種,都是BSD/Linux爲加速IO操作而提供的異步IO模型
2. ngx_event_thread_process_posted
這個函數檢查event表,並調用event對應的handler函數,每次處理1個event。
這兩個函數組合使用,就實現了最基本的m:n併發模型。
nginx代碼分析之(二)——Empty Gif是如何工作的
訪問新浪時,時常會有一些網頁返回空白(但不是“此頁無法顯示”),從瀏覽器的信息中可以知道此時服務器返回了一個1×1的空白gif圖片。
這實際上是nginx實現的,nginx有一個名爲Empty Gif的module,專門負責此項工作。
由於這個module比較簡單,我們就先從它入手,來看看nginx的模塊實現。
模塊註冊Empty Gif這個module只有一個文件——ngx_http_empty_gif_module.c
這個文件比較簡單,一開始定義並初始化了3個變量。
static ngx_command_t ngx_http_empty_gif_commands[] = {...};
static ngx_http_module_t ngx_http_empty_gif_module_ctx = {...};
ngx_module_t ngx_http_empty_gif_module = {...};
其中只有ngx_http_empty_gif_module是非靜態的,我將暫時將其稱爲module主結構變量,
而其餘兩個變量都可以由它訪問到。
但是如果繼續查看nginx的源碼,會發現沒有其他地方引用ngx_http_empty_gif_module,
那這個module是怎麼註冊並應用起來的呢?
如果熟悉Apache的代碼,會發現這和Apache 2.0的module機制非常類似——每個module都對應到一個module主結構變量,通過這個主結構變量可以訪問到這個module的其他內容,該module所有的函數也用函數指針的方式存放在這些結構變量中。
而且Apache同樣沒有其他地方的代碼引用到module主結構變量。這是因爲module不是必須的,該module在某一個特定的編譯版本里是可以不存在的。因此一個module是否有效,不是通過代碼來決定,而是通過編譯選項來實現。
在nginx代碼的auto目錄中,有一個名爲sources的文件,根據編譯選項(configure的參數)的不同,m4宏變量HTTP_MODULES的值會發生變化:
如果指定了使用empty gif模塊(默認就是使用了),則最終m4宏變量HTTP_MODULES的值可能如下:
HTTP_MODULES="ngx_http_module /
ngx_http_core_module /
ngx_http_log_module /
ngx_http_upstream_module /
ngx_http_empty_gif_module "
注意:這裏的ngx_http_empty_gif_module字符串對應了ngx_http_empty_gif_module.c文件中的Module主結構變量名。
編譯之前的configure結束後,會在objs目錄下生成一個名爲ngx_modules.c的文件,此文件的內容如下:
#include
#include
extern ngx_module_t ngx_core_module;
extern ngx_module_t ngx_errlog_module;
extern ngx_module_t ngx_conf_module;
...
extern ngx_module_t ngx_http_empty_gif_module;
...
ngx_module_t *ngx_modules[] = {
&ngx_core_module,
&ngx_errlog_module,
&ngx_conf_module,
...
&ngx_http_empty_gif_module,
...
NULL
};
在此生成了對ngx_http_empty_gif_module變量的引用,並將其放到了ngx_modules表中,
通過相關函數可以進行存取。
這樣,在編譯時就完成了Empty Gif模塊註冊的過程。
模塊的初始化和應用初始化一般都是根據配置文件的內容來進行,但和我們一般寫程序的做法不同——nginx並沒有在一個統一的地方處理所有的配置,而是讓每個模塊負責處理自己的配置項,如果沒有編譯這個模塊,則其對應的配置項就無法處理,這也是又一個和Apache的相似之處。
nginx使用了ngx_command_t結構來描述某一個模塊對應的配置項及處理函數。
以Empty Gif模塊爲例:
static ngx_command_t ngx_http_empty_gif_commands[] = {
{ ngx_string("empty_gif"),
NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
ngx_http_empty_gif,
0,
0,
NULL },
0);"> ngx_null_command
};
上面的定義表明:
1. Empty Gif模塊只處理一個配置項——“empty_gif”
2. 這個配置是一個Location相關的配置(NGX_HTTP_LOC_CONF),
即只有在處理某一個URL子集,如 /test_[0-9]*.gif時才生效。
實際的配置文件可能如下:
location ~ /test_[0-9].gif {
empty_gif;
}
3. 這個配置項不帶參數(NGX_CONF_NOARGS)
4. 配置處理函數是ngx_http_empty_gif
ngx_http_empty_gif函數的實現很簡單:
static char *
ngx_http_empty_gif(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_loc_conf_t *clcf;
clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
clcf->handler = ngx_http_empty_gif_handler;
return NGX_CONF_OK;
}
ngx_http_conf_get_module_loc_conf是一個宏,用於獲得Location相關的配置表cf中ngx_http_core_module對應的項,獲取之後,Empty Gif模塊將自己的處理函數掛到了ngx_http_core_module對應的handler上。
這樣,nginx在處理HTTP請求時,如果發現其URL匹配到Empty Gif所屬的Location,
如URL(/test_1.gif)匹配到Location(/test_[0-9].gif),
則使用ngx_http_empty_gif作爲處理函數,這個函數直接向瀏覽器寫回一幅1×1的空白gif圖片。
本文轉自
http://www.sameparty.com/x/?action=show&id=626
nginx代碼分析之(一)——初探
不知道原創,作者聯繫下我吧。
他的代碼我全看過了,感覺是高層模型下做的最優精簡指令。效果還是不錯的。
發現nginx是無意間在瀏覽器中看到新浪的一個錯誤頁面“nginx ...”,不由起了好奇心,google了一把,發現這是一個支持負載均衡的反向代理服務器,俄羅斯人開發的,雖然沒有走GNU或BSD的License,但是也算是一個開源軟件。
開源代理服務器最熟悉的還是Squid和Apache,但這兩者都是正反向代理通吃的,而作爲反向代理,實際上和正向代理有較大的差別。我想既然新浪也用它,那自然有它的獨到之處。查了一下,中文的網頁上說它的HTTP性能可以達到13000TPS以上,但是沒有說明數據的出處,國外的網站上暫時找不到相應的數據,但很多人拿它和lighttpd相比。
很快下載了nginx 0.5.32版本的代碼,代碼不多,才8萬多行,在openssl的基礎上支持HTTPS。和Apache的30多萬行相比,精簡了很多,
作爲web server或反向代理,要的就是一個快,要做到快,除了精簡的代碼之外,更關鍵的一點就是併發模型。
Apache的弱點就在於它的併發模型是普通的進程/線程池,連接數和進程/線程數是1:1的,因此無論是prefork還是worker模式,都將每一個連接對應到一個獨立的進程/線程。
這樣的併發模型在連接數不太多(1000以內)時還算可以,但在大規模併發時,其進程/線程總數會非常多。由於Apache本身也比較吃內存,所以到了1000以上的併發時,服務器的內存基本上也就被吃的差不多了,操作系統也在頻繁地做進程/線程的切換,非常吃力。
相比之下,更高級的大型網絡服務系統(如電信的智能網系統)一般採用進程/線程池+狀態機的模型——也即接數和進程/線程數是m:n的,這樣進程/線程總數就不會由於連接的增多而增多,避免了內存和調度切換的開銷,但這種做法對程序邏輯的要求較高,需要一個連接拆分爲多個邏輯狀態(創建,讀,寫,關閉等,根據實際業務還可以更加細化)每個進程/線程處理完某一種狀態後,需要改變該連接的狀態值,後續狀態由下一個空閒的進程/線程處理。
nginx就採用了這樣的併發模型,對於連接狀態的存儲,nginx主要採用了這樣一個複雜結構。
struct ngx_connection_s {
void *data;
ngx_event_t *read;
ngx_event_t *write;
...
};
結構ngx_event_t存儲了連接IO狀態的詳細信息,同時所有的ngx_event_t組成了兩個全局的鏈表,以便進行存取操作。
在這兩個數據結構的基礎上,nginx使用了下面這兩個函數來完成每個進程/線程的循環
1. ngx_locked_post_event
這個函數負責更新某一個連接的狀態,在檢查到連接IO狀態改變(比如通過select)後被調用。
nginx以module的方式提供了select語義的多種實現:
poll
devpoll
epoll
eventport
kqueue
rtsig
後面4種,都是BSD/Linux爲加速IO操作而提供的異步IO模型
2. ngx_event_thread_process_posted
這個函數檢查event表,並調用event對應的handler函數,每次處理1個event。
這兩個函數組合使用,就實現了最基本的m:n併發模型。
nginx代碼分析之(二)——Empty Gif是如何工作的
訪問新浪時,時常會有一些網頁返回空白(但不是“此頁無法顯示”),從瀏覽器的信息中可以知道此時服務器返回了一個1×1的空白gif圖片。
這實際上是nginx實現的,nginx有一個名爲Empty Gif的module,專門負責此項工作。
由於這個module比較簡單,我們就先從它入手,來看看nginx的模塊實現。
模塊註冊Empty Gif這個module只有一個文件——ngx_http_empty_gif_module.c
這個文件比較簡單,一開始定義並初始化了3個變量。
static ngx_command_t ngx_http_empty_gif_commands[] = {...};
static ngx_http_module_t ngx_http_empty_gif_module_ctx = {...};
ngx_module_t ngx_http_empty_gif_module = {...};
其中只有ngx_http_empty_gif_module是非靜態的,我將暫時將其稱爲module主結構變量,
而其餘兩個變量都可以由它訪問到。
但是如果繼續查看nginx的源碼,會發現沒有其他地方引用ngx_http_empty_gif_module,
那這個module是怎麼註冊並應用起來的呢?
如果熟悉Apache的代碼,會發現這和Apache 2.0的module機制非常類似——每個module都對應到一個module主結構變量,通過這個主結構變量可以訪問到這個module的其他內容,該module所有的函數也用函數指針的方式存放在這些結構變量中。
而且Apache同樣沒有其他地方的代碼引用到module主結構變量。這是因爲module不是必須的,該module在某一個特定的編譯版本里是可以不存在的。因此一個module是否有效,不是通過代碼來決定,而是通過編譯選項來實現。
在nginx代碼的auto目錄中,有一個名爲sources的文件,根據編譯選項(configure的參數)的不同,m4宏變量HTTP_MODULES的值會發生變化:
如果指定了使用empty gif模塊(默認就是使用了),則最終m4宏變量HTTP_MODULES的值可能如下:
HTTP_MODULES="ngx_http_module /
ngx_http_core_module /
ngx_http_log_module /
ngx_http_upstream_module /
ngx_http_empty_gif_module "
注意:這裏的ngx_http_empty_gif_module字符串對應了ngx_http_empty_gif_module.c文件中的Module主結構變量名。
編譯之前的configure結束後,會在objs目錄下生成一個名爲ngx_modules.c的文件,此文件的內容如下:
#include
#include
extern ngx_module_t ngx_core_module;
extern ngx_module_t ngx_errlog_module;
extern ngx_module_t ngx_conf_module;
...
extern ngx_module_t ngx_http_empty_gif_module;
...
ngx_module_t *ngx_modules[] = {
&ngx_core_module,
&ngx_errlog_module,
&ngx_conf_module,
...
&ngx_http_empty_gif_module,
...
NULL
};
在此生成了對ngx_http_empty_gif_module變量的引用,並將其放到了ngx_modules表中,
通過相關函數可以進行存取。
這樣,在編譯時就完成了Empty Gif模塊註冊的過程。
模塊的初始化和應用初始化一般都是根據配置文件的內容來進行,但和我們一般寫程序的做法不同——nginx並沒有在一個統一的地方處理所有的配置,而是讓每個模塊負責處理自己的配置項,如果沒有編譯這個模塊,則其對應的配置項就無法處理,這也是又一個和Apache的相似之處。
nginx使用了ngx_command_t結構來描述某一個模塊對應的配置項及處理函數。
以Empty Gif模塊爲例:
static ngx_command_t ngx_http_empty_gif_commands[] = {
{ ngx_string("empty_gif"),
NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
ngx_http_empty_gif,
0,
0,
NULL },
0);"> ngx_null_command
};
上面的定義表明:
1. Empty Gif模塊只處理一個配置項——“empty_gif”
2. 這個配置是一個Location相關的配置(NGX_HTTP_LOC_CONF),
即只有在處理某一個URL子集,如 /test_[0-9]*.gif時才生效。
實際的配置文件可能如下:
location ~ /test_[0-9].gif {
empty_gif;
}
3. 這個配置項不帶參數(NGX_CONF_NOARGS)
4. 配置處理函數是ngx_http_empty_gif
ngx_http_empty_gif函數的實現很簡單:
static char *
ngx_http_empty_gif(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_loc_conf_t *clcf;
clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
clcf->handler = ngx_http_empty_gif_handler;
return NGX_CONF_OK;
}
ngx_http_conf_get_module_loc_conf是一個宏,用於獲得Location相關的配置表cf中ngx_http_core_module對應的項,獲取之後,Empty Gif模塊將自己的處理函數掛到了ngx_http_core_module對應的handler上。
這樣,nginx在處理HTTP請求時,如果發現其URL匹配到Empty Gif所屬的Location,
如URL(/test_1.gif)匹配到Location(/test_[0-9].gif),
則使用ngx_http_empty_gif作爲處理函數,這個函數直接向瀏覽器寫回一幅1×1的空白gif圖片。
本文轉自
http://www.sameparty.com/x/?action=show&id=626
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.