nginx源碼導讀
⑴ 閱讀nginx源代碼 使用什麼編輯器
」, 除了閱讀代碼以外, 沒有更好的方法. 7.在尋找bug時, 請從問題的表現形式到問題的根源來分析代碼. 不要沿著不相關的路徑(誤入歧途). 8.我們要充分利用調試器|編譯器給出的警告或輸出的符號代碼|系統調用跟蹤器|資料庫結構化查詢語言的日誌機制...
⑵ 如何用Nginx源碼製作RPM包的詳解
1、查看操作系統版本和內核版本
2、創建相關目錄
/usr/src/redhat/SOURCES //存放源代碼,補丁,圖標等文件。
/usr/src/redhat/SPECS //存放用於管理rpm製作進程的spec文件。
/usr/src/redhat/BUILD //解壓後的文件存放在這里。
/usr/src/redhat/RPMS //存放由rpmbuild製作好的二進制包。
/usr/src/redhat/SRPMS //存放由rpmbuild製作好的源碼包。
3、下載Nginx源碼包
下載源碼包到SOURCES目錄,不需要解壓。
4、手工創建SPEC文件,由於spec文件是由spec語言編寫的,請注意spec語言的語法。
SPEC文件內容如下:
#############################
# Example Spec File For Nginx
# Edited By LaoXu 7.Mar.2013
#############################
Summary: High Performance Web Server
Name: nginx
Version: 1.3.9
Release: el5
License: GPL
Group: Applications/Server
Source:
URL:
Distribution: Linux
Packager: XuYuanzhen <absolutey.>
%description
nginx [engine x] is a HTTP and reverse proxy server, as well as a mail proxy server
%prep
rm -rf $RPM_BUILD_DIR/nginx-1.3.9
zcat $RPM_SOURCE_DIR/nginx-1.3.9.tar
⑶ nginx log format 中分別對應request中的那些變數.
是這樣子的,nginx的ngx_http_variables.c文件中對於nginx內置的http變數進行了定義。
從nginx的源碼來分析,修改headers_in中的host成員是不會修改$host變數的值的。
如下是nginx的代碼:
{ngx_string("http_host"),NULL,ngx_http_variable_header,
offsetof(ngx_http_request_t,headers_in.host),0,0},
{ngx_string("host"),NULL,ngx_http_variable_host,0,0,0},
/**
*從如上的nginx變數的定義可知,對於$http_host變數,對應的才是headers_in結構體的host*成員。
*$host變數是通過ngx_http_variable_host函數去獲取的。
*接下來,我們看ngx_http_variable_host的函數定義。
*/
staticngx_int_t
ngx_http_variable_host(ngx_http_request_t*r,ngx_http_variable_value_t*v,
uintptr_tdata)
{
ngx_http_core_srv_conf_t*cscf;
if(r->headers_in.server.len){
v->len=r->headers_in.server.len;
v->data=r->headers_in.server.data;
}else{
cscf=ngx_http_get_mole_srv_conf(r,ngx_http_core_mole);
v->len=cscf->server_name.len;
v->data=cscf->server_name.data;
}
v->valid=1;
v->no_cacheable=0;
v->not_found=0;
returnNGX_OK;
}
/**
*從函數定義可知,$host變數的值實際上是取得header_in結構中的server成員。如果該成員*為空,取得的是配置文件中的server_name指令的值。
*/
因此,通過上述的分析,你修改了header_in的host成員,$host變數不變是正常的。可以用$http_host來代替$host來試試。
全部來自轉載並非原創
⑷ nginx哪本書好
《深入理解Nginx》,講nginx原理,講如何模塊開發。
配合這本書可以閱讀nginx源碼。
⑸ 如何nginx的源代碼目錄然後編譯
1.只刪除的/usr/local/nginx 的這樣刪除不完全,因為會有其他配置或lib中分散再其他地方
2.make clean 只是清除編譯時產生的 .o 檔
3.建議 config 時加入 prefix 摻數指定軟體安裝位置
4.如果你只是想重新編譯或是換別的版本,沒有刪除無所謂那無所謂,重新 config ;make ;make install 即可
⑹ Nginx是什麼,有什麼優點
Nginx是一個高性能的 HTTP 和 反向代理 伺服器,也是一個 IMAP/POP3/SMTP 代理伺服器。因它的穩定性、豐富的功能集、示例配置文件和低系統資源的消耗而聞名。2011年6月1日,nginx 1.0.4發布。
優點:
(1)更快
這表現在兩個方面:一方面,在正常情況下,單次請求會得到更快的響應;另一方面,在高峰期(如有數以萬計的並發請求),Nginx可以比其他Web伺服器更快地響應請求。
(2)高擴展性,跨平台
Nginx的設計極具擴展性,它完全是由多個不同功能、不同層次、不同類型且耦合度極低的模塊組成。因此,當對某一個模塊修復Bug或進行升級時,可以專
注於模塊自身,無須在意其他。而且在HTTP模塊中,還設計了HTTP過濾器模塊:一個正常的HTTP模塊在處理完請求後,會有一串HTTP過濾器模塊對
請求的結果進行再處理。這樣,當我們開發一個新的HTTP模塊時,不但可以使用諸如HTTP核心模塊、events模塊、log模塊等不同層次或者不同類
型的模塊,還可以原封不動地復用大量已有的HTTP過濾器模塊。這種低耦合度的優秀設計,造就了Nginx龐大的第三方模塊,當然,公開的第三方模塊也如
官方發布的模塊一樣容易使用。
Nginx的模塊都是嵌入到二進制文件中執行的,無論官方發布的模塊還是第三方模塊都是如此。這使得第三方模塊一樣具備極其優秀的性能,充分利用Nginx的高並發特性,因此,許多高流量的網站都傾向於開發符合自己業務特性的定製模塊。
(3)高可靠性:用於反向代理,宕機的概率微乎其微
高可靠性是我們選擇Nginx的最基本條件,因為Nginx的可靠性是大家有目共睹的,很多家高流量網站都在核心伺服器上大規模使用Nginx。
Nginx的高可靠性來自於其核心框架代碼的優秀設計、模塊設計的簡單性;另外,官方提供的常用模塊都非常穩定,每個worker進程相對獨
立,master進程在1個worker進程出錯時可以快速「拉起」新的worker子進程提供服務。
(4)低內存消耗
一般情況下,10 000個非活躍的HTTP Keep-Alive連接在Nginx中僅消耗2.5MB的內存,這是Nginx支持高並發連接的基礎。
(5)單機支持10萬以上的並發連接
這是一個非常重要的特性!隨著互聯網的迅猛發展和互聯網用戶數量的成倍增長,各大公司、網站都需要應付海量並發請求,一個能夠在峰值期頂住10萬以上並發
請求的Server,無疑會得到大家的青睞。理論上,Nginx支持的並發連接上限取決於內存,10萬遠未封頂。當然,能夠及時地處理更多的並發請求,是
與業務特點緊密相關的。
(6)熱部署
master管理進程與worker工作進程的分離設計,使得Nginx能夠提供熱部署功能,即可以在7×24小時不間斷服務的前提下,升級Nginx的可執行文件。當然,它也支持不停止服務就更新配置項、更換日誌文件等功能。
(7)最自由的BSD許可協議
這是Nginx可以快速發展的強大動力。BSD許可協議不只是允許用戶免費使用Nginx,它還允許用戶在自己的項目中直接使用或修改Nginx源碼,然後發布。這吸引了無數開發者繼續為Nginx貢獻自己的智慧。
以上7個特點當然不是Nginx的全部,擁有無數個官方功能模塊、第三方功能模塊使得Nginx能夠滿足絕大部分應用場景,這些功能模塊間可以疊加以實現
更加強大、復雜的功能,有些模塊還支持Nginx與Perl、Lua等腳本語言集成工作,大大提高了開發效率。這些特點促使用戶在尋找一個Web伺服器時
更多考慮Nginx。
選擇Nginx的核心理由還是它能在支持高並發請求的同時保持高效的服務。
⑺ 怎樣查看nginx源碼
penResty是一個nginx lua擴展,其作者對nginx非常熟悉,也是很多模塊的貢獻者。
去看看這個openresty/lua-nginx-mole · GitHub,它的文檔其實能闡述nginx的幾個PHASE是怎麼聯系在一塊的,當然你要先大概知道ngx的11個PHASE。
⑻ 如何解讀Nginx源碼
前提:
1、首先nginx是C語言編寫的,你必須知識要有C語言的編程基礎,否則很痛苦
2、了解web伺服器,反向代理的基本知識,以及HTTP協議,TCP/IP協議的基本知識
如果你已經有豐富的經驗,或者是大牛,那前面的前提就是廢話,可以略過。
看源碼准備:
1、找官網,找貢獻者的博客去了解NGINX是做什麼的,有什麼特性,性能,功能,架構等
2、下載源代碼,從分析main函數開始,大致了解啟動流程,初始化以及一些程序的啟動准備
3、建議找到request邏輯,分析下對請求的整個處理流程,不用很細,慢慢來,一口吃不了大胖子,有問題就先記上再說
4、根據分析request的經驗,拓展分析下nginx的模塊,處理鏈,以及封裝的數據結構如ngx_str_t,ngx_event_t等數據結構
5、到網上找個例子,自己動手去寫個模塊,或修改某個處理邏輯,你一定會遇到問題,這時你可以通過GDB等工具進行分析和調試,這樣加深了你的理解
6、動手寫代碼,看源碼,調試,重復這個過程。
其他
多在網路上找資源和志同道和的技術愛好者或牛人,多交流溝通。
堅持一年,你會有突飛猛進的成績。good luck
⑼ nginx 源碼 epoll模塊在哪個文件
Linux平台上,Nginx使用epoll完成事件驅動,實現高並發;本文將不對epoll本身進行介紹(網上一堆一堆的文章介紹epoll的原理及使用方法,甚至源碼分析等),僅看一下Nginx是如何使用epoll的。
Nginx在epoll模塊中定義了好幾個函數,這些函數基本都是作為回調注冊到事件抽象層的對應介面上,從而實現了事件驅動的具體化,我們看如下的一段代碼:
[cpp] view plain print?
ngx_event_mole_t ngx_epoll_mole_ctx = {
&epoll_name,
ngx_epoll_create_conf, /* create configuration */
ngx_epoll_init_conf, /* init configuration */
{
ngx_epoll_add_event, /* add an event */
ngx_epoll_del_event, /* delete an event */
ngx_epoll_add_event, /* enable an event */
ngx_epoll_del_event, /* disable an event */
ngx_epoll_add_connection, /* add an connection */
ngx_epoll_del_connection, /* delete an connection */
NULL, /* process the changes */
ngx_epoll_process_events, /* process the events */
ngx_epoll_init, /* init the events */
ngx_epoll_done, /* done the events */
}
};
這段代碼就是epoll的相關函數注冊到事件抽象層,這里所謂的事件抽象層在前面的博文中有提過,就是Nginx為了方便支持和開發具體的I/O模型,從而實現的一層抽象。代碼後面的注釋將功能說明得很詳細了,本文就只重點關注ngx_epoll_init和ngx_epoll_process_events兩個函數,其他幾個函數就暫且忽略了。
ngx_epoll_init主要是完成epoll的相關初始化工作,代碼分析如下:
[cpp] view plain print?
static ngx_int_t
ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
{
ngx_epoll_conf_t *epcf;
/*取得epoll模塊的配置結構*/
epcf = ngx_event_get_conf(cycle->conf_ctx, ngx_epoll_mole);
/*ep是epoll模塊定義的一個全局變數,初始化為-1*/
if (ep == -1) {
/*創一個epoll對象,容量為總連接數的一半*/
ep = epoll_create(cycle->connection_n / 2);
if (ep == -1) {
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
"epoll_create() failed");
return NGX_ERROR;
}
}
/*nevents也是epoll模塊定義的一個全局變數,初始化為0*/
if (nevents < epcf->events) {
if (event_list) {
ngx_free(event_list);
}
/*event_list存儲產生事件的數組*/
event_list = ngx_alloc(sizeof(struct epoll_event) * epcf->events,
cycle->log);
if (event_list == NULL) {
return NGX_ERROR;
}
}
nevents = epcf->events;
/*初始化全局變數ngx_io, ngx_os_is定義為:
ngx_os_io_t ngx_os_io = {
ngx_unix_recv,
ngx_readv_chain,
ngx_udp_unix_recv,
ngx_unix_send,
ngx_writev_chain,
0
};(位於src/os/unix/ngx_posix_init.c)
*/
ngx_io = ngx_os_io;
/*這里就是將epoll的具體介面函數注冊到事件抽象層介面ngx_event_actions上。
具體是上文提到的ngx_epoll_mole_ctx中封裝的如下幾個函數
ngx_epoll_add_event,
ngx_epoll_del_event,
ngx_epoll_add_event,
ngx_epoll_del_event,
ngx_epoll_add_connection,
ngx_epoll_del_connection,
ngx_epoll_process_events,
ngx_epoll_init,
ngx_epoll_done,
*/
ngx_event_actions = ngx_epoll_mole_ctx.actions;
#if (NGX_HAVE_CLEAR_EVENT)
/*epoll將添加這個標志,主要為了實現邊緣觸發*/
ngx_event_flags = NGX_USE_CLEAR_EVENT
#else
/*水平觸發*/
ngx_event_flags = NGX_USE_LEVEL_EVENT
#endif
|NGX_USE_GREEDY_EVENT /*io的時候,直到EAGAIN為止*/
|NGX_USE_EPOLL_EVENT; /*epoll標志*/
return NGX_OK;
}
epoll初始化工作沒有想像中的復雜,和我們平時使用epoll都一樣,下面看ngx_epoll_process_events,這個函數主要用來完成事件的等待並處理。
[cpp] view plain print?
static ngx_int_t
ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
{
int events;
uint32_t revents;
ngx_int_t instance, i;
ngx_uint_t level;
ngx_err_t err;
ngx_log_t *log;
ngx_event_t *rev, *wev, **queue;
ngx_connection_t *c;
/*一開始就是等待事件,最長等待時間為timer;nginx為事件
專門用紅黑樹維護了一個計時器。後續對這個timer單獨分析。
*/
events = epoll_wait(ep, event_list, (int) nevents, timer);
if (events == -1) {
err = ngx_errno;
} else {
err = 0;
}
if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
/*執行一次時間更新, nginx將時間緩存到了一組全局變數中,方便程序高效的獲取事件。*/
ngx_time_update();
}
/*處理wait錯誤*/
if (err) {
if (err == NGX_EINTR) {
if (ngx_event_timer_alarm) {
ngx_event_timer_alarm = 0;
return NGX_OK;
}
level = NGX_LOG_INFO;
} else {
level = NGX_LOG_ALERT;
}
ngx_log_error(level, cycle->log, err, "epoll_wait() failed");
return NGX_ERROR;
}
/*wait返回事件數0,可能是timeout返回,也可能是非timeout返回;非timeout返回則是error*/
if (events == 0) {
if (timer != NGX_TIMER_INFINITE) {
return NGX_OK;
}
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
"epoll_wait() returned no events without timeout");
return NGX_ERROR;
}
log = cycle->log;
/*for循環開始處理收到的所有事件*/
for (i = 0; i < events; i++) {
/*取得發生此事件的連接*/
c = event_list[i].data.ptr;
instance = (uintptr_t) c & 1;
c = (ngx_connection_t *) ((uintptr_t) c & (uintptr_t) ~1);
/*獲得該連接上的讀事件*/
rev = c->read;
。。。。。。。。。。。。。
/*取得發生一個事件*/
revents = event_list[i].events;
/*記錄wait的錯誤返回狀態*/
if (revents & (EPOLLERR|EPOLLHUP)) {
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, log, 0,
"epoll_wait() error on fd:%d ev:%04XD",
c->fd, revents);
}
if ((revents & (EPOLLERR|EPOLLHUP))
&& (revents & (EPOLLIN|EPOLLOUT)) == 0)
{
/*
* if the error events were returned without EPOLLIN or EPOLLOUT,
* then add these flags to handle the events at least in one
* active handler
*/
revents |= EPOLLIN|EPOLLOUT;
}
/*該事件是一個讀事件,並該連接上注冊的讀事件是active的*/
if ((revents & EPOLLIN) && rev->active) {
if ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) {
rev->posted_ready = 1;
} else {
rev->ready = 1;
}
/*事件放入相應的隊列中;關於此處的先入隊再處理,在前面的文章中已經介紹過了。*/
if (flags & NGX_POST_EVENTS) {
queue = (ngx_event_t **) (rev->accept ?
&ngx_posted_accept_events : &ngx_posted_events);
ngx_locked_post_event(rev, queue); /*入隊*/
} else {
rev->handler(rev);
}
}
wev = c->write;
/*發生的是一個寫事件,和讀事件完全一樣的邏輯過程*/
if ((revents & EPOLLOUT) && wev->active) {
if (flags & NGX_POST_THREAD_EVENTS) {
wev->posted_ready = 1;
} else {
wev->ready = 1;
}
/*先入隊再處理*/
if (flags & NGX_POST_EVENTS) {
ngx_locked_post_event(wev, &ngx_posted_events);
} else {
wev->handler(wev);
}
}
}
return NGX_OK;
}
本文將關注的兩個epoll函數也就這么一點代碼了,但整個epoll還有添加事件和刪除事件等的相關函數,代碼都很簡單,本文就不做具體的分析了。
寫到此處的時候,我感覺epoll模塊沒有分析的足夠詳細,或者說是沒有足夠的理解作者的用意,如果你有更好的理解,希望能夠告訴我。或許,隨著後面的分析,能夠逐漸的真正明白吧。