Nginx深入詳解之模組化體系結構
在開始嘮叨之前,先簡單介紹下配置系統,因為之後的東東會與這個有一定的關係。
一、配置系統
Nginx的配置系統由一個主配置檔案和一些輔助配置檔案構成,這些配置檔案預設在/etc/nginx/目錄下。
輔助配置檔案只在某些特定情況下才會使用,但主配置檔案即nginx.conf是在任何情況下都必須使用的。
在nginx.conf中,包含若干配置項,每個配置項由配置指令和指令引數兩部分組成,指令引數即配置指令對應的配置值,可以簡單認為配置項是一個Key/Value對。
需要注意的是,配置指令如果包含空格需要用單引號或雙引號括起來,指令引數如果是由簡單字串構成的簡單配置項則需要以分號結束,如果指令引數是複雜配置項則需要用{}括起來。
nginx.conf中的配置資訊,根據其邏輯上的意義對其進行分類,可以分成多個作用域或指令上下文,指令上下文層次關係如下:
main:Nginx在執行時與具體業務功能無關的引數,比如工作程序數、執行身份等。
http:與提供http服務相關的引數,比如keepalive、gzip等。
server:http服務上支援若干虛擬機器,每個虛擬機器一個對應的server配置項,配置項裡包含該虛擬機器相關的配置。
location:http服務中,某些特定的URL對應的一系列配置項。
mail: 實現email相關的SMTP/IMAP/POP3代理時,共享的一些配置項。
二、模組體系
Nginx的內部結構是由核心部分和一系列功能模組組成的,這樣可以使得每個模組的功能相對簡單,便於對系統進行功能擴充套件,各模組之間的關係如下圖:
nginx core實現了底層的通訊協議,為其他模組和Nginx程序構建了基本的執行時環境,並且構建了其他各模組的協作基礎。
http模組和mail模組位於nginx core和各功能模組的中間層,這2個模組在nginx core之上實現了另外一層抽象,分別處理與http協議和email相關協議(SMTP/IMAP/POP3)有關的事件,並且確保這些事件能被以正確的順序呼叫其它的一些功能模組。
nginx功能模組基本上分為如下幾種型別:
(1) event module:搭建了獨立於作業系統的事件處理機制的框架,以及提供了各具體事件的處理,包括ngx_event_module、ngx_event_core_module和ngx_epoll_module等,Nginx具體使用何種事件處理模組,這依賴於具體的作業系統和編譯選項。
(2) phase handler:此型別的模組也被直接稱為handler模組,主要負責處理客戶端請求併產生待響應內容,比如ngx_http_module模組,負責客戶端的靜態頁面請求處理並將對應的磁碟檔案準備為響應內容輸出。
(3) output filter:也稱為filter模組,主要是負責對輸出的內容進行處理,可以對輸出進行修改,比如可以實現對輸出的所有html頁面增加預定義的footbar一類的工作,或者對輸出的圖片的URL進行替換之類的工作。
(4) upstream:實現反向代理功能,將真正的請求轉發到後端伺服器上,並從後端伺服器上讀取響應,發回客戶端,upstream模組是一種特殊的handler,只不過響應內容不是真正由自己產生的,而是從後端伺服器上讀取的。
(5) load-balancer:負載均衡模組,實現特定的演算法,在眾多的後端伺服器中,選擇一個伺服器出來作為某個請求的轉發伺服器。
(6) extend module:根據特定業務需要編寫的第三方模組。
三、請求處理
下面將會以http請求處理為例來說明請求、配置和模組是如何串起來的。
當Nginx讀取到一個HTTP Request的header時,首先查詢與這個請求關聯的虛擬主機的配置,如果找到了則這個請求會經歷以下幾個階段的處理(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: 內容產生階段
NGX_HTTP_LOG_PHASE:日誌模組處理階段
在內容產生階段,為了給一個request產生正確的response,Nginx必須把這個請求交給一個合適的content handler去處理。如果這個request對應的location在配置檔案中被明確指定了一個content handler,那麼Nginx就可以通過對location的匹配,直接找到這個對應的handler,並把這request交給這個content handler去處理。這樣的配置指令包括perl、flv、proxy_pass、mp4等。
如果一個request對應的location並沒有直接配置的content handler,那麼Nginx依次作如下嘗試:
(1) 如果一個location裡面有配置random_index on,那麼隨即選擇一個檔案傳送給客戶端。
(2) 如果一個location裡面有配置index指令,那麼傳送index指令指定的檔案給客戶端。
(3) 如果一個location裡面有配置autoindex on,那麼就傳送請求地址對應的服務端路徑下的檔案列表給客戶端。
(4) 如果這個request對應的location上有設定gzip_static on,那麼就查詢是否有對應的.gz檔案存在,如果有的話,就傳送這個客戶端(客戶端支援gzip的情況下).
(5) 請求的URI如果對應的一個靜態檔案,static module就傳送靜態檔案的內容到客戶端。
內容產生階段完成以後,生成的輸出會被傳遞到filter模組去進行處理。filter模組也是與location相關的。所有的filter模組都被組織成了一條鏈。輸出會依次穿越所有的filter,直到有一個filter模組的返回值表明已經處理完成。 接下來就可以傳送response給客戶端了。