nginx淺析

Nginx淺析html

目錄nginx

一、簡述... 1web

二、Nginx功能概述... 1算法

三、Nginx 架構... 2後端

四、Nginx 基礎概念... 3緩存

五、Nginx 的模塊化體系結構... 5服務器

六、Nginx工做原理... 6網絡

一、反向代理與正向代理... 6數據結構

二、Nginx模塊... 7多線程

三、Nginx請求處理... 9

參考文獻:... 17

 

一、簡述

Nginx 是一個高性能的HTTP和反向代理服務器,同時也是一個 IMAP/POP3/SMTP 代理服務器。Nginx 以事件驅動的方式編寫,因此有很是好的性能,同時也是一個很是高效的反向代理、負載平衡。

二、Nginx功能概述

_HTTP基礎功能:__

處理靜態文件,索引文件以及自動索引;

反向代理加速(無緩存),簡單的負載均衡和容錯;

FastCGI,簡單的負載均衡和容錯;

模塊化的結構。過濾器包括gzipping, byte ranges, chunked responses, 以及 SSI-filter 。在SSI過濾器中,到同一個 proxy 或者 FastCGI 的多個子請求併發處理;

SSL 和 TLS SNI 支持;

__其餘HTTP功能:

基於IP 和名稱的虛擬主機服務;

Memcached 的 GET 接口;

支持 keep-alive 和管道鏈接;

靈活簡單的配置;

從新配置和在線升級而無須中斷客戶的工做進程;

可定製的訪問日誌,日誌寫入緩存,以及快捷的日誌回捲;

4xx-5xx 錯誤代碼重定向;

基於 PCRE 的 rewrite 重寫模塊;

基於客戶端 IP 地址和 HTTP 基本認證的訪問控制;

PUT, DELETE, 和 MKCOL 方法;

支持 FLV (Flash 視頻);

帶寬限制;

__IMAP/POP3 代理服務功能:

使用外部 HTTP 認證服務器重定向用戶到 IMAP/POP3 後端;

使用外部 HTTP 認證服務器認證用戶後鏈接重定向到內部的 SMTP 後端;

認證方法:

POP3: POP3 USER/PASS, APOP, AUTH LOGIN PLAIN CRAM-MD5;

IMAP: IMAP LOGIN;

SMTP: AUTH LOGIN PLAIN CRAM-MD5;

SSL 支持;

在 IMAP 和 POP3 模式下的 STARTTLS 和 STLS 支持;

__支持的操做系統:

FreeBSD 3.x, 4.x, 5.x, 6.x i386; FreeBSD 5.x, 6.x amd64;

Linux 2.2, 2.4, 2.6 i386; Linux 2.6 amd64;

Solaris 8 i386; Solaris 9 i386 and sun4u; Solaris 10 i386;

MacOS X (10.4) PPC;

__結構與擴展:

一個主進程和多個工做進程。工做進程是單線程的,且不須要特殊受權便可運行;

kqueue (FreeBSD 4.1+), epoll (Linux 2.6+), rt signals (Linux 2.2.19+), /dev/poll (Solaris 7 11/99+), select, 以及 poll 支持;

kqueue支持的不一樣功能包括 EV_CLEAR, EV_DISABLE (臨時禁止事件), NOTE_LOWAT, EV_EOF, 有效數據的數目,錯誤代碼;

sendfile (FreeBSD 3.1+), sendfile (Linux 2.2+), sendfile64 (Linux 2.4.21+), 和 sendfilev (Solaris 8 7/01+) 支持;

輸入過濾 (FreeBSD 4.1+) 以及 TCP_DEFER_ACCEPT (Linux 2.4+) 支持;

10,000 非活動的 HTTP keep-alive 鏈接僅須要 2.5M 內存。

最小化的數據拷貝操做;

 

本文主要關注nginx做爲http服務器的基礎功能

三、Nginx 架構

Nginx 是以多進程的方式來工做的,進程包含一個 master 進程和多個 worker 進程。master 進程主要用來管理 worker 進程,包含:接收來自外界的信號,向各 worker 進程發送信號,監控 worker 進程的運行狀態,當 worker 進程退出後(異常狀況下),會自動從新啓動新的 worker 進程。而基本的網絡事件,則是放在 worker 進程中來處理了。多個 worker 進程之間是對等的,他們同等競爭來自客戶端的請求,各進程互相之間是獨立的。一個請求,只可能在一個 worker 進程中處理,一個 worker 進程,不可能處理其它進程的請求。worker 進程的個數是能夠設置的,通常咱們會設置與機器cpu核數一致,這裏面的緣由與 Nginx 的進程模型以及事件處理模型是分不開的。Nginx 的進程模型,能夠由下圖來表示:

 

從上文中咱們能夠看到,master 來管理 worker 進程,因此咱們只須要與 master 進程通訊就好了。master 進程會接收來自外界發來的信號,再根據信號作不一樣的事情。因此咱們要控制 Nginx,只須要向 master 進程發送信號就好了。

四、Nginx 基礎概念

       Connection:在 Nginx 中 connection 就是對 tcp 鏈接的封裝,其中包括鏈接的 socket,讀事件,寫事件。利用 Nginx 封裝的 connection,咱們能夠很方便的使用 Nginx 來處理與鏈接相關的事情,好比,創建鏈接,發送與接受數據等。結合一個 tcp 鏈接的生命週期,咱們看看 Nginx 是如何處理一個鏈接的。首先,Nginx 在啓動時,會解析配置文件,獲得須要監聽的端口與 ip 地址,而後在 Nginx 的 master 進程裏面,先初始化好這個監控的 socket(建立 socket,設置 addrreuse 等選項,綁定到指定的 ip 地址端口,再 listen),而後再 fork 出多個子進程出來,而後子進程會競爭 accept 新的鏈接。此時,客戶端就能夠向 Nginx 發起鏈接了。當客戶端與服務端經過三次握手創建好一個鏈接後,Nginx 的某一個子進程會 accept 成功,獲得這個創建好的鏈接的 socket,而後建立 Nginx 對鏈接的封裝,即 ngx_connection_t 結構體。接着,設置讀寫事件處理函數並添加讀寫事件來與客戶端進行數據的交換。最後,Nginx 或客戶端來主動關掉鏈接,到此,一個鏈接就壽終正寢了。

       Request:在 Nginx 中咱們指的是 http 請求,具體到 Nginx 中的數據結構是ngx_http_request_t。ngx_http_request_t 是對一個 http 請求的封裝。 Nginx 經過 ngx_http_request_t 來保存解析請求與輸出響應相關的數據。下面是 Nginx 處理一個完整的請求的處理流程圖;

 

Keepalive:在 Nginx 中,對於 http1.0 與 http1.1 也是支持長鏈接的。什麼是長鏈接呢?咱們知道,http 請求是基於 TCP 協議之上的,那麼,當客戶端在發起請求前,須要先與服務端創建 TCP 鏈接,而每一次的 TCP 鏈接是須要三次握手來肯定的,若是客戶端與服務端之間網絡差一點,這三次交互消費的時間會比較多,並且三次交互也會帶來網絡流量。固然,當鏈接斷開後,也會有四次的交互,固然對用戶體驗來講就不重要了。而 http 請求是請求應答式的,若是咱們能知道每一個請求頭與響應體的長度,那麼咱們是能夠在一個鏈接上面執行多個請求的,這就是所謂的長鏈接,但前提條件是咱們先得肯定請求頭與響應體的長度。

Pipe:pipeline 其實就是流水線做業,它能夠看做爲 keepalive 的一種昇華,由於 pipeline 也是基於長鏈接的,目的就是利用一個鏈接作屢次請求。若是客戶端要提交多個請求,對於keepalive來講,那麼第二個請求,必需要等到第一個請求的響應接收徹底後,才能發起,這和 TCP 的中止等待協議是同樣的,獲得兩個響應的時間至少爲2*RTT。而對 pipeline 來講,客戶端沒必要等到第一個請求處理完後,就能夠立刻發起第二個請求。獲得兩個響應的時間可能可以達到1*RTT。Nginx 是直接支持 pipeline 的,可是,Nginx 對 pipeline 中的多個請求的處理卻不是並行的,依然是一個請求接一個請求的處理,只是在處理第一個請求的時候,客戶端就能夠發起第二個請求。這樣,Nginx 利用 pipeline 減小了處理完一個請求後,等待第二個請求的請求頭數據的時間。其實 Nginx 的作法很簡單,前面說到,Nginx 在讀取數據時,會將讀取的數據放到一個 buffer 裏面,因此,若是 Nginx 在處理完前一個請求後,若是發現 buffer 裏面還有數據,就認爲剩下的數據是下一個請求的開始,而後就接下來處理下一個請求,不然就設置 keepalive。

lingering_close:lingering_close,字面意思就是延遲關閉,也就是說,當 Nginx 要關閉鏈接時,並不是當即關閉鏈接,而是先關閉 tcp 鏈接的寫,再等待一段時間後再關掉鏈接的讀。

五、Nginx 的模塊化體系結構

       Nginx 的內部結構是由核心部分和一系列的功能模塊所組成。核心部分(Nginx core)實現了底層的通信協議,爲其餘模塊和 Nginx 進程構建了基本的運行時環境,而且構建了其餘各模塊的協做基礎。除此以外,或者說大部分與協議相關的,或者應用相關的功能都是在這些模塊中所實現的。

Nginx 的模塊根據其功能基本上能夠分爲如下幾種類型:

event module: 搭建了獨立於操做系統的事件處理機制的框架,及提供了各具體事件的處理。包括 ngx_events_module, ngx_event_core_module和ngx_epoll_module 等。Nginx 具體使用何種事件處理模塊,這依賴於具體的操做系統和編譯選項。

phase handler: 此類型的模塊也被直接稱爲 handler 模塊。主要負責處理客戶端請求併產生待響應內容,好比 ngx_http_static_module 模塊,負責客戶端的靜態頁面請求處理並將對應的磁盤文件準備爲響應內容輸出。

output filter: 也稱爲 filter 模塊,主要是負責對輸出的內容進行處理,能夠對輸出進行修改。例如,能夠實現對輸出的全部 html 頁面增長預約義的 footbar 一類的工做,或者對輸出的圖片的 URL 進行替換之類的工做。

upstream: upstream 模塊實現反向代理的功能,將真正的請求轉發到後端服務器上,並從後端服務器上讀取響應,發回客戶端。upstream 模塊是一種特殊的 handler,只不過響應內容不是真正由本身產生的,而是從後端服務器上讀取的。

load-balancer: 負載均衡模塊,實現特定的算法,在衆多的後端服務器中,選擇一個服務器出來做爲某個請求的轉發服務器。

六、Nginx工做原理

一、反向代理與正向代理

       反向代理(Reverse Proxy)方式是指以代理服務器來接受internet上的鏈接請求,而後將請求轉發給內部網絡上的服務器,並將從服務器上獲得的結果返回給internet上請求鏈接的客戶端,此時代理服務器對外就表現爲一個服務器。

 

正向代理(Forward Proxy)一般都被簡稱爲代理,就是在用戶沒法正常訪問外部資源,比方說受到GFW的影響沒法訪問twitter的時候,咱們能夠經過代理的方式,讓用戶繞過防火牆,從而鏈接到目標網絡或者服務。

 

二、Nginx模塊

     一、模塊劃分

nginx有五大優勢:模塊化、事件驅動、異步、非阻塞、多進程單線程。由內核和模塊組成的,其中內核完成的工做比較簡單,僅僅經過查找配置文件將客戶端請求映射到一個location block,而後又將這個location block中所配置的每一個指令將會啓動不一樣的模塊去完成相應的工做。

Nginx的模塊從結構上分爲核心模塊、基礎模塊和第三方模塊:

核心模塊:HTTP模塊、EVENT模塊和MAIL模塊

基礎模塊:HTTP Access模塊、HTTP FastCGI模塊、HTTP Proxy模塊和HTTP Rewrite模塊,

第三方模塊:HTTP Upstream Request Hash模塊、Notice模塊和HTTP Access Key模塊。

 

Nginx的模塊從功能上分爲以下四類:

Core(核心模塊):構建nginx基礎服務、管理其餘模塊。

Handlers(處理器模塊):此類模塊直接處理請求,並進行輸出內容和修改headers信息等操做。

Filters (過濾器模塊):此類模塊主要對其餘處理器模塊輸出的內容進行修改操做,最後由Nginx輸出。

Proxies (代理類模塊):此類模塊是Nginx的HTTP Upstream之類的模塊,這些模塊主要與後端一些服務好比FastCGI等進行交互,實現服務代理和負載均衡等功能。

 

Nginx的核心模塊主要負責創建nginx服務模型、管理網絡層和應用層協議、以及啓動針對特定應用的一系列候選模塊。其餘模塊負責分配給web服務器的實際工做:

(1) 當Nginx發送文件或者轉發請求到其餘服務器,由Handlers(處理模塊)或Proxies(代理類模塊)提供服務;

(2) 當須要Nginx把輸出壓縮或者在服務端加一些東西,由Filters(過濾模塊)提供服務。

 

二、模塊處理

當服務器啓動,每一個handlers(處理模塊)都有機會映射到配置文件中定義的特定位置(location);若是有多個handlers(處理模塊)映射到特定位置時,只有一個會「贏」(說明配置文件有衝突項,應該避免發生)。

處理模塊以三種形式返回:

 

OK

ERROR

或者放棄處理這個請求而讓默認處理模塊來處理(主要是用來處理一些靜態文件,事實上若是是位置正確而真實的靜態文件,默認的處理模塊會搶先處理)。

若是handlers(處理模塊)把請求反向代理到後端的服務器,就變成另一類的模塊:load-balancers(負載均衡模塊)。負載均衡模塊的配置中有一組後端服務器,當一個HTTP請求過來時,它決定哪臺服務器應當得到這個請求。

Nginx的負載均衡模塊採用兩種方法:

 

輪轉法,它處理請求就像紙牌遊戲同樣從頭至尾分發;

 

IP哈希法,在衆多請求的狀況下,它確保來自同一個IP的請求會分發到相同的後端服務器。

 

若是handlers(處理模塊)沒有產生錯誤,filters(過濾模塊)將被調用。多個filters(過濾模塊)能映射到每一個位置,因此(好比)每一個請求均可以被壓縮成塊。它們的執行順序在編譯時決定。

filters(過濾模塊)是經典的「接力鏈表(CHAIN OF RESPONSIBILITY)」模型:一個filters(過濾模塊)被調用,完成其工做,而後調用下一個filters(過濾模塊),直到最後一個filters(過濾模塊)。

 

過濾模塊鏈的特別之處在於:

 

每一個filters(過濾模塊)不會等上一個filters(過濾模塊)所有完成;

 

它能把前一個過濾模塊的輸出做爲其處理內容;有點像Unix中的流水線;

 

過濾模塊能以buffer(緩衝區)爲單位進行操做,這些buffer通常都是一頁(4K)大小,固然你也能夠在nginx.conf文件中進行配置。這意味着,好比,模塊能夠壓縮來自後端服務器的響應,而後像流同樣的到達客戶端,直到整個響應發送完成。總之,過濾模塊鏈以流水線的方式高效率地向客戶端發送響應信息。

總結下上面的內容,一個典型的HTTP處理週期是這樣的:

客戶端發送HTTP請求 –>

Nginx基於配置文件中的位置選擇一個合適的處理模塊 ->

(若是有)負載均衡模塊選擇一臺後端服務器 –>

處理模塊進行處理並把輸出緩衝放到第一個過濾模塊上 –>

第一個過濾模塊處理後輸出給第二個過濾模塊 –>

而後第二個過濾模塊又到第三個 –>

依此類推 –> 最後把響應發給客戶端。

 

下圖展現了Nginx模塊處理流程:

 

Nginx自己作的工做實際不多,當它接到一個HTTP請求時,它僅僅是經過查找配置文件將這次請求映射到一個location block,而此location中所配置的各個指令則會啓動不一樣的模塊去完成工做,所以模塊能夠看作Nginx真正的勞動工做者。一般一個location中的指令會涉及一個handler模塊和多個filter模塊(固然,多個location能夠複用同一個模塊)。handler模塊負責處理請求,完成響應內容的生成,而filter模塊對響應內容進行處理

三、Nginx請求處理

Nginx在啓動時會以daemon形式在後臺運行,採用多進程+異步非阻塞IO事件模型來處理各類鏈接請求。多進程模型包括一個master進程,多個worker進程,通常worker進程個數是根據服務器CPU核數來決定的。master進程負責管理Nginx自己和其餘worker進程。以下圖:

 

從上圖中能夠很明顯地看到,4個worker進程的父進程都是master進程,代表worker進程都是從父進程fork出來的,而且父進程的ppid爲1,表示其爲daemon進程。

 

須要說明的是,在nginx多進程中,每一個worker都是平等的,所以每一個進程處理外部請求的機會權重都是一致的。

 

Master進程的做用是:

讀取並驗證配置文件nginx.conf;管理worker進程;

Worker進程的做用是:

每個Worker進程都維護一個線程(避免線程切換),處理鏈接和請求;注意Worker進程的個數由配置文件決定,通常和CPU個數相關(有利於進程切換),配置幾個就有幾個Worker進程。

 

Nginx如何作到熱部署?

所謂熱部署,就是配置文件nginx.conf修改後,不須要stop Nginx,不須要中斷請求,就能讓配置文件生效!(nginx -s reload 從新加載/nginx -t檢查配置/nginx -s stop)

經過上文咱們已經知道worker進程負責處理具體的請求,那麼若是想達到熱部署的效果,能夠想象:

方案一:

修改配置文件nginx.conf後,主進程master負責推送給woker進程更新配置信息,woker進程收到信息後,更新進程內部的線程信息。

方案二:

修改配置文件nginx.conf後,從新生成新的worker進程,固然會以新的配置進行處理請求,並且新的請求必須都交給新的worker進程,至於老的worker進程,等把那些之前的請求處理完畢後,kill掉便可。

Nginx採用的就是方案二來達到熱部署的!

 

Nginx掛了怎麼辦?

Nginx既然做爲入口網關,很重要,若是出現單點問題,顯然是不可接受的。

答案是:Keepalived+Nginx實現高可用。

Keepalived是一個高可用解決方案,主要是用來防止服務器單點發生故障,能夠經過和Nginx配合來實現Web服務的高可用。(其實,Keepalived不只僅能夠和Nginx配合,還能夠和不少其餘服務配合)

Keepalived+Nginx實現高可用的思路:

第一:請求不要直接打到Nginx上,應該先經過Keepalived(這就是所謂虛擬IP,VIP)

第二:Keepalived應該能監控Nginx的生命狀態(提供一個用戶自定義的腳本,按期檢查Nginx進程狀態,進行權重變化,,從而實現Nginx故障切換)

 

Nginx架構及工做流程圖:

 

Nginx真正處理請求業務的是Worker之下的線程。worker進程中有一個ngx_worker_process_cycle()函數,執行無限循環,不斷處理收到的來自客戶端的請求,並進行處理,直到整個Nginx服務被中止。

 

worker 進程中,ngx_worker_process_cycle()函數就是這個無限循環的處理函數。在這個函數中,一個請求的簡單處理流程以下:

操做系統提供的機制(例如 epoll, kqueue 等)產生相關的事件。

接收和處理這些事件,如是接收到數據,則產生更高層的 request 對象。

處理 request 的 header 和 body。

產生響應,併發送回客戶端。

完成 request 的處理。

從新初始化定時器及其餘事件。

3.1 多進程處理模型

下面來介紹一個請求進來,多進程模型的處理方式:

首先,master進程一開始就會根據咱們的配置,來創建須要listen的網絡socket fd,而後fork出多個worker進程。

其次,根據進程的特性,新創建的worker進程,也會和master進程同樣,具備相同的設置。所以,其也會去監聽相同ip端口的套接字socket fd。

而後,這個時候有多個worker進程都在監聽一樣設置的socket fd,意味着當有一個請求進來的時候,全部的worker都會感知到。這樣就會產生所謂的「驚羣現象」。爲了保證只會有一個進程成功註冊到listenfd的讀事件,nginx中實現了一個「accept_mutex」相似互斥鎖,只有獲取到這個鎖的進程,才能夠去註冊讀事件。其餘進程所有accept 失敗。

最後,監聽成功的worker進程,讀取請求,解析處理,響應數據返回給客戶端,斷開鏈接,結束。所以,一個request請求,只須要worker進程就能夠完成。

進程模型的處理方式帶來的一些好處就是:進程之間是獨立的,也就是一個worker進程出現異常退出,其餘worker進程是不會受到影響的;此外,獨立進程也會避免一些不須要的鎖操做,這樣子會提升處理效率,而且開發調試也更容易。

如前文所述,多進程模型+異步非阻塞模型纔是勝出的方案。單純的多進程模型會致使鏈接併發數量的下降,而採用異步非阻塞IO模型很好的解決了這個問題;而且還所以避免的多線程的上下文切換致使的性能損失。

worker進程會競爭監聽客戶端的鏈接請求:這種方式可能會帶來一個問題,就是可能全部的請求都被一個worker進程給競爭獲取了,致使其餘進程都比較空閒,而某一個進程會處於忙碌的狀態,這種狀態可能還會致使沒法及時響應鏈接而丟棄discard掉本有能力處理的請求。這種不公平的現象,是須要避免的,尤爲是在高可靠web服務器環境下。

針對這種現象,Nginx採用了一個是否打開accept_mutex選項的值,ngx_accept_disabled標識控制一個worker進程是否須要去競爭獲取accept_mutex選項,進而獲取accept事件。

ngx_accept_disabled值:nginx單進程的全部鏈接總數的八分之一,減去剩下的空閒鏈接數量,獲得的這個ngx_accept_disabled。

當ngx_accept_disabled大於0時,不會去嘗試獲取accept_mutex鎖,而且將ngx_accept_disabled減1,因而,每次執行到此處時,都會去減1,直到小於0。不去獲取accept_mutex鎖,就是等於讓出獲取鏈接的機會,很顯然能夠看出,當空閒鏈接越少時,ngx_accept_disable越大,因而讓出的機會就越多,這樣其它進程獲取鎖的機會也就越大。不去accept,本身的鏈接就控制下來了,其它進程的鏈接池就會獲得利用,這樣,nginx就控制了多進程間鏈接的平衡了。

3.2 一個簡單的HTTP請求

從 Nginx 的內部來看,一個 HTTP Request 的處理過程涉及到如下幾個階段:

初始化 HTTP Request(讀取來自客戶端的數據,生成 HTTP Request 對象,該對象含有該請求全部的信息)。

處理請求頭。

處理請求體。

若是有的話,調用與此請求(URL 或者 Location)關聯的 handler。

依次調用各 phase handler 進行處理。

在創建鏈接過程當中,對於nginx監聽到的每一個客戶端鏈接,都會將它的讀事件的handler設置爲ngx_http_init_request函數,這個函數就是請求處理的入口。在處理請求時,主要就是要解析http請求,好比:uri,請求行等,而後再根據請求生成響應。下面看一下nginx處理的具體過程:

 

在這裏,咱們須要瞭解一下 phase handler 這個概念。phase 字面的意思,就是階段。因此 phase handlers 也就好理解了,就是包含若干個處理階段的一些 handler。

在每個階段,包含有若干個 handler,再處理到某個階段的時候,依次調用該階段的 handler 對 HTTP Request 進行處理。

一般狀況下,一個 phase handler 對這個 request 進行處理,併產生一些輸出。一般 phase handler 是與定義在配置文件中的某個 location 相關聯的。

一個 phase handler 一般執行如下幾項任務:

獲取 location 配置。

產生適當的響應。

發送 response header。

發送 response body。

當 Nginx 讀取到一個 HTTP Request 的 header 的時候,Nginx 首先查找與這個請求關聯的虛擬主機的配置。若是找到了這個虛擬主機的配置,那麼一般狀況下,這個 HTTP Request 將會通過如下幾個階段的處理(phase handlers):

NGX_HTTP_POST_READ_PHASE: 讀取請求內容階段

NGX_HTTP_SERVER_REWRITE_PHASE: Server 請求地址重寫階段

NGX_HTTP_FIND_CONFIG_PHASE: 配置查找階段

NGX_HTTP_REWRITE_PHASE: Location請求地址重寫階段

NGX_HTTP_POST_REWRITE_PHASE: 請求地址重寫提交階段

NGX_HTTP_PREACCESS_PHASE: 訪問權限檢查準備階段

NGX_HTTP_ACCESS_PHASE: 訪問權限檢查階段

NGX_HTTP_POST_ACCESS_PHASE: 訪問權限檢查提交階段

NGX_HTTP_TRY_FILES_PHASE: 配置項 try_files 處理階段

NGX_HTTP_CONTENT_PHASE: 內容產生階段

NGX_HTTP_LOG_PHASE: 日誌模塊處理階段

在內容產生階段,爲了給一個 request 產生正確的響應,Nginx 必須把這個 request 交給一個合適的 content handler 去處理。若是這個 request 對應的 location 在配置文件中被明確指定了一個 content handler,那麼Nginx 就能夠經過對 location 的匹配,直接找到這個對應的 handler,並把這個 request 交給這個 content handler 去處理。這樣的配置指令包括像,perl,flv,proxy_pass,mp4等。

若是一個 request 對應的 location 並無直接有配置的 content handler,那麼 Nginx 依次嘗試:

若是一個 location 裏面有配置 random_index on,那麼隨機選擇一個文件,發送給客戶端。

若是一個 location 裏面有配置 index 指令,那麼發送 index 指令指明的文件,給客戶端。

若是一個 location 裏面有配置 autoindex on,那麼就發送請求地址對應的服務端路徑下的文件列表給客戶端。

若是這個 request 對應的 location 上有設置 gzip_static on,那麼就查找是否有對應的.gz文件存在,有的話,就發送這個給客戶端(客戶端支持 gzip 的狀況下)。

請求的 URI 若是對應一個靜態文件,static module 就發送靜態文件的內容到客戶端。

內容產生階段完成之後,生成的輸出會被傳遞到 filter 模塊去進行處理。filter 模塊也是與 location 相關的。全部的 filter 模塊都被組織成一條鏈。輸出會依次穿越全部的 filter,直到有一個 filter 模塊的返回值代表已經處理完成。

這裏列舉幾個常見的 filter 模塊,例如:

server-side includes。

XSLT filtering。

圖像縮放之類的。

gzip 壓縮。

在全部的 filter 中,有幾個 filter 模塊須要關注一下。按照調用的順序依次說明以下:

copy: 將一些須要複製的 buf(文件或者內存)從新複製一份而後交給剩餘的 body filter 處理。

postpone: 這個 filter 是負責 subrequest 的,也就是子請求的。

write: 寫輸出到客戶端,其實是寫到鏈接對應的 socket 上。

3.3 請求完整處理過程

根據以上請求步驟所述,請求完整的處理過程以下圖所示:

 

參考文獻:

https://www.jianshu.com/p/6215e5d24553

http://www.javashuo.com/article/p-svivqglt-ho.html

https://www.w3cschool.cn/nginx/hwa71pe6.html

http://www.nginx.cn/doc/index.html

相關文章
相關標籤/搜索