鍍金池/ 教程/ Linux/ Nginx 的請求處理
示例: hello handler 模塊
什么是 Nginx
handler 模塊的掛載
Nginx 特點
handler 模塊簡介
初探 Nginx 架構(gòu)
Nginx 的模塊化體系結(jié)構(gòu)
更多 handler 模塊示例分析
Nginx 基礎(chǔ)概念
upstream 模塊簡介
Nginx 的請求處理
過濾模塊簡介
基本數(shù)據(jù)結(jié)構(gòu)
模塊的基本結(jié)構(gòu)
負(fù)載均衡模塊
過濾模塊的分析
core 模塊
handler 模塊的基本結(jié)構(gòu)
Nginx 的配置系統(tǒng)
handler 的編寫步驟
handler 模塊的編譯和使用
event 模塊

Nginx 的請求處理

Nginx 使用一個多進(jìn)程模型來對外提供服務(wù),其中一個 master 進(jìn)程,多個 worker 進(jìn)程。master 進(jìn)程負(fù)責(zé)管理 Nginx 本身和其他 worker 進(jìn)程。

所有實際上的業(yè)務(wù)處理邏輯都在 worker 進(jìn)程。worker 進(jìn)程中有一個函數(shù),執(zhí)行無限循環(huán),不斷處理收到的來自客戶端的請求,并進(jìn)行處理,直到整個 Nginx 服務(wù)被停止。

worker 進(jìn)程中,ngx_worker_process_cycle()函數(shù)就是這個無限循環(huán)的處理函數(shù)。在這個函數(shù)中,一個請求的簡單處理流程如下:

  • 操作系統(tǒng)提供的機(jī)制(例如 epoll, kqueue 等)產(chǎn)生相關(guān)的事件。
  • 接收和處理這些事件,如是接受到數(shù)據(jù),則產(chǎn)生更高層的 request 對象。
  • 處理 request 的 header 和 body。
  • 產(chǎn)生響應(yīng),并發(fā)送回客戶端。
  • 完成 request 的處理。
  • 重新初始化定時器及其他事件。

請求的處理流程

為了讓大家更好的了解 Nginx 中請求處理過程,我們以 HTTP Request 為例,來做一下詳細(xì)地說明。

從 Nginx 的內(nèi)部來看,一個 HTTP Request 的處理過程涉及到以下幾個階段。

  • 初始化 HTTP Request(讀取來自客戶端的數(shù)據(jù),生成 HTTP Request 對象,該對象含有該請求所有的信息)。
  • 處理請求頭。
  • 處理請求體。
  • 如果有的話,調(diào)用與此請求(URL 或者 Location)關(guān)聯(lián)的 handler。
  • 依次調(diào)用各 phase handler 進(jìn)行處理。

在這里,我們需要了解一下 phase handler 這個概念。phase 字面的意思,就是階段。所以 phase handlers 也就好理解了,就是包含若干個處理階段的一些 handler。

在每一個階段,包含有若干個 handler,再處理到某個階段的時候,依次調(diào)用該階段的 handler 對 HTTP Request 進(jìn)行處理。

通常情況下,一個 phase handler 對這個 request 進(jìn)行處理,并產(chǎn)生一些輸出。通常 phase handler 是與定義在配置文件中的某個 location 相關(guān)聯(lián)的。

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

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

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

  • NGX_HTTP_POST_READ_PHASE: 讀取請求內(nèi)容階段
  • 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: 訪問權(quán)限檢查準(zhǔn)備階段
  • NGX_HTTP_ACCESS_PHASE: 訪問權(quán)限檢查階段
  • NGX_HTTP_POST_ACCESS_PHASE: 訪問權(quán)限檢查提交階段
  • NGX_HTTP_TRY_FILES_PHASE: 配置項 try_files 處理階段
  • NGX_HTTP_CONTENT_PHASE: 內(nèi)容產(chǎn)生階段
  • NGX_HTTP_LOG_PHASE: 日志模塊處理階段

在內(nèi)容產(chǎn)生階段,為了給一個 request 產(chǎn)生正確的響應(yīng),Nginx 必須把這個 request 交給一個合適的 content handler 去處理。如果這個 request 對應(yīng)的 location 在配置文件中被明確指定了一個 content handler,那么Nginx 就可以通過對 location 的匹配,直接找到這個對應(yīng)的 handler,并把這個 request 交給這個 content handler 去處理。這樣的配置指令包括像,perl,flv,proxy_pass,mp4等。

如果一個 request 對應(yīng)的 location 并沒有直接有配置的 content handler,那么 Nginx 依次嘗試:

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

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

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

  • server-side includes。
  • XSLT filtering。
  • 圖像縮放之類的。
  • gzip 壓縮。

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

  • write: 寫輸出到客戶端,實際上是寫到連接對應(yīng)的 socket 上。
  • postpone: 這個 filter 是負(fù)責(zé) subrequest 的,也就是子請求的。
  • copy: 將一些需要復(fù)制的 buf(文件或者內(nèi)存)重新復(fù)制一份然后交給剩余的 body filter 處理。
上一篇:core 模塊下一篇:handler 模塊的掛載