NGINX的模塊化

nginx的內(nèi)部結(jié)構(gòu)是由核心部分和一系列的功能模塊所組成。這樣劃分是為了使得每個(gè)模塊的功能相對(duì)簡(jiǎn)單,便于開(kāi)發(fā),同時(shí)也便于對(duì)系統(tǒng)進(jìn)行功能擴(kuò)展。為了便于描述,下文中我們將使用nginx core來(lái)稱呼nginx的核心功能部分。
nginx提供了web服務(wù)器的基礎(chǔ)功能,同時(shí)提供了web服務(wù)反向代理,email服務(wù)反向代理功能。nginx core實(shí)現(xiàn)了底層的通訊協(xié)議,為其他模塊和nginx進(jìn)程構(gòu)建了基本的運(yùn)行時(shí)環(huán)境,并且構(gòu)建了其他各模塊的協(xié)作基礎(chǔ)。除此之外,或者說(shuō)大部分與協(xié)議相關(guān)的,或者應(yīng)用相關(guān)的功能都是在這些模塊中所實(shí)現(xiàn)的。我們的RTMP服務(wù)同樣以模塊的形式實(shí)現(xiàn)。

模塊概述

nginx將各功能模塊組織成一條鏈,當(dāng)有請(qǐng)求到達(dá)的時(shí)候,請(qǐng)求依次經(jīng)過(guò)這條鏈上的部分或者全部模塊,進(jìn)行處理。每個(gè)模塊實(shí)現(xiàn)特定的功能。例如,實(shí)現(xiàn)對(duì)請(qǐng)求解壓縮的模塊,實(shí)現(xiàn)SSI的模塊,實(shí)現(xiàn)與上游服務(wù)器進(jìn)行通訊的模塊,實(shí)現(xiàn)與FastCGI服務(wù)進(jìn)行通訊的模塊。
有兩個(gè)模塊比較特殊,他們居于nginx core和各功能模塊的中間。這兩個(gè)模塊就是http模塊和mail模塊。這2個(gè)模塊在nginx core之上實(shí)現(xiàn)了另外一層抽象,處理與HTTP協(xié)議和email相關(guān)協(xié)議(SMTP/POP3/IMAP)有關(guān)的事件,并且確保這些事件能被以正確的順序調(diào)用其他的一些功能模塊。
目前HTTP協(xié)議是被實(shí)現(xiàn)在http模塊中的,但是有可能將來(lái)被剝離到一個(gè)單獨(dú)的模塊中,以擴(kuò)展nginx支持SPDY協(xié)議。

模塊的分類

nginx的模塊根據(jù)其功能基本上可以分為以下幾種類型:

  • event module:
    搭建了獨(dú)立于操作系統(tǒng)的事件處理機(jī)制的框架,及提供了各具體事件的處理。包括ngx_events_module, ngx_event_core_module和ngx_epoll_module等。nginx具體使用何種事件處理模塊,這依賴于具體的操作系統(tǒng)和編譯選項(xiàng)。
  • phase handler:
    此類型的模塊也被直接稱為handler模塊。主要負(fù)責(zé)處理客戶端請(qǐng)求并產(chǎn)生待響應(yīng)內(nèi)容,比如ngx_http_static_module模塊,負(fù)責(zé)客戶端的靜態(tài)頁(yè)面請(qǐng)求處理并將對(duì)應(yīng)的磁盤文件準(zhǔn)備為響應(yīng)內(nèi)容輸出。
  • output filter:
    也稱為filter模塊,主要是負(fù)責(zé)對(duì)輸出的內(nèi)容進(jìn)行處理,可以對(duì)輸出進(jìn)行修改。例如,可以實(shí)現(xiàn)對(duì)輸出的所有html頁(yè)面增加預(yù)定義的footbar一類的工作,或者對(duì)輸出的圖片的URL進(jìn)行替換之類的工作。
  • upstream:
    upstream模塊實(shí)現(xiàn)反向代理的功能,將真正的請(qǐng)求轉(zhuǎn)發(fā)到后端服務(wù)器上,并從后端服務(wù)器上讀取響應(yīng),發(fā)回客戶端。upstream模塊是一種特殊的handler,只不過(guò)響應(yīng)內(nèi)容不是真正由自己產(chǎn)生的,而是從后端服務(wù)器上讀取的。
  • load-balancer:
    負(fù)載均衡模塊,實(shí)現(xiàn)特定的算法,在眾多的后端服務(wù)器中,選擇一個(gè)服務(wù)器出來(lái)作為某個(gè)請(qǐng)求的轉(zhuǎn)發(fā)服務(wù)器。

請(qǐng)求的處理流程

為了讓大家更好的了解nginx中請(qǐng)求處理過(guò)程,我們以HTTP Request為例,來(lái)做一下詳細(xì)地說(shuō)明。
從nginx的內(nèi)部來(lái)看,一個(gè)HTTP Request的處理過(guò)程涉及到以下幾個(gè)階段。

  1. 初始化HTTP Request(讀取來(lái)自客戶端的數(shù)據(jù),生成HTTP Request對(duì)象,該對(duì)象含有該請(qǐng)求所有的信息)。
  2. 處理請(qǐng)求頭。
  3. 處理請(qǐng)求體。
  4. 如果有的話,調(diào)用與此請(qǐng)求(URL或者Location)關(guān)聯(lián)的handler。
  5. 依次調(diào)用各phase handler進(jìn)行處理。
    在這里,我們需要了解一下phase handler這個(gè)概念。phase字面的意思,就是階段。所以phase handlers也就好理解了,就是包含若干個(gè)處理階段的一些handler。
    在每一個(gè)階段,包含有若干個(gè)handler,再處理到某個(gè)階段的時(shí)候,依次調(diào)用該階段的handler對(duì)HTTP Request進(jìn)行處理。
    通常情況下,一個(gè)phase handler對(duì)這個(gè)request進(jìn)行處理,并產(chǎn)生一些輸出。通常phase handler是與定義在配置文件中的某個(gè)location相關(guān)聯(lián)的。

一個(gè)phase handler通常執(zhí)行以下幾項(xiàng)任務(wù):

  1. 獲取location配置。
  2. 產(chǎn)生適當(dāng)?shù)捻憫?yīng)。
  3. 發(fā)送response header。
  4. 發(fā)送response body。

當(dāng)nginx讀取到一個(gè)HTTP Request的header的時(shí)候,nginx首先查找與這個(gè)請(qǐng)求關(guān)聯(lián)的虛擬主機(jī)的配置。如果找到了這個(gè)虛擬主機(jī)的配置,那么通常情況下,這個(gè)HTTP Request將會(huì)經(jīng)過(guò)以下幾個(gè)階段的處理(phase handlers):

  1. NGX_HTTP_POST_READ_PHASE: 讀取請(qǐng)求內(nèi)容階段
  2. NGX_HTTP_SERVER_REWRITE_PHASE: Server請(qǐng)求地址重寫(xiě)階段
  3. NGX_HTTP_FIND_CONFIG_PHASE: 配置查找階段:
  4. NGX_HTTP_REWRITE_PHASE: Location請(qǐng)求地址重寫(xiě)階段
  5. NGX_HTTP_POST_REWRITE_PHASE: 請(qǐng)求地址重寫(xiě)提交階段
  6. NGX_HTTP_PREACCESS_PHASE: 訪問(wèn)權(quán)限檢查準(zhǔn)備階段
  7. NGX_HTTP_ACCESS_PHASE: 訪問(wèn)權(quán)限檢查階段
  8. NGX_HTTP_POST_ACCESS_PHASE: 訪問(wèn)權(quán)限檢查提交階段
  9. NGX_HTTP_TRY_FILES_PHASE: 配置項(xiàng)try_files處理階段
  10. NGX_HTTP_CONTENT_PHASE:內(nèi)容產(chǎn)生階段
  11. NGX_HTTP_LOG_PHASE: 日志模塊處理階段
    在內(nèi)容產(chǎn)生階段,為了給一個(gè)request產(chǎn)生正確的響應(yīng),nginx必須把這個(gè)request交給一個(gè)合適的content handler去處理。如果這個(gè)request對(duì)應(yīng)的location在配置文件中被明確指定了一個(gè)content handler,那么nginx就可以通過(guò)對(duì)location的匹配,直接找到這個(gè)對(duì)應(yīng)的handler,并把這個(gè)request交給這個(gè)content handler去處理。這樣的配置指令包括像,perl,flv,proxy_pass,mp4等。

如果一個(gè)request對(duì)應(yīng)的location并沒(méi)有直接有配置的content handler,那么nginx依次嘗試:

  1. 如果一個(gè)location里面有配置 random_index on,那么隨機(jī)選擇一個(gè)文件,發(fā)送給客戶端。
  2. 如果一個(gè)location里面有配置 index指令,那么發(fā)送index指令指明的文件,給客戶端。
  3. 如果一個(gè)location里面有配置 autoindex on,那么就發(fā)送請(qǐng)求地址對(duì)應(yīng)的服務(wù)端路徑下的文件列表給客戶端。
  4. 如果這個(gè)request對(duì)應(yīng)的location上有設(shè)置gzip_static on,那么就查找是否有對(duì)應(yīng)的.gz文件存在,有的話,就發(fā)送這個(gè)給客戶端(客戶端支持gzip的情況下)。
  5. 請(qǐng)求的URI如果對(duì)應(yīng)一個(gè)靜態(tài)文件,static module就發(fā)送靜態(tài)文件的內(nèi)容到客戶端。

內(nèi)容產(chǎn)生階段完成以后,生成的輸出會(huì)被傳遞到filter模塊去進(jìn)行處理。filter模塊也是與location相關(guān)的。所有的fiter模塊都被組織成一條鏈。輸出會(huì)依次穿越所有的filter,直到有一個(gè)filter模塊的返回值表明已經(jīng)處理完成。
這里列舉幾個(gè)常見(jiàn)的filter模塊,例如:

  1. server-side includes。
  2. XSLT filtering。
  3. 圖像縮放之類的。
  4. gzip壓縮。

在所有的filter中,有幾個(gè)filter模塊需要關(guān)注一下。按照調(diào)用的順序依次說(shuō)明如下:

  1. write:寫(xiě)輸出到客戶端,實(shí)際上是寫(xiě)到連接對(duì)應(yīng)的socket上。
  2. postpone:這個(gè)filter是負(fù)責(zé)subrequest的,也就是子請(qǐng)求的。
  3. copy:將一些需要復(fù)制的buf(文件或者內(nèi)存)重新復(fù)制一份然后交給剩余的body filter處理。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容