程式與模組(一)
簡介
Nginx 的程式碼是由一個 核心 和一系列的 模組 組成。
Nginx 由核心和一系列模組組成:核心提供web服務的基本功能,如啟用網路協議、建立執行環境、接收和分配客戶端請求、處理模組之間的互動。模組實現Nginx的各種功能和操作,Nginx的模組從結構上分為核心模組、基礎模組和第三方模組。
- 核心模組:HTTP模組、EVENT模組和MAIL模組
- 基礎模組:HTTP Access模組、HTTP FastCGI模組、HTTP Proxy模組和HTTP Rewrite模組
- 第三方模組:HTTP Upstream Request Hash模組、Notice模組和HTTP Access Key模組及使用者自己開發的模組
這樣的設計使 Nginx 方便開發和擴充套件,也正因此才使得 Nginx 功能如此強大。Nginx 的模組預設編譯進 Nginx 中,如果需要增加或刪除模組,需要重新編譯 Nginx,這一點不如 Apache 的動態載入模組方便。如果有需要動態載入模組,可以使用由淘寶網發起的 Web 伺服器 Tengine,在 Nginx 的基礎上增加了很多高階特性,完全相容 Nginx,已被國內很多網站採用。
程式
首先我們要知道 Nginx 是以多程式的方式進行工作的。Nginx在Linux系統啟動後,會以守護程式(daemon)的方式在後臺執行,後臺程式包括一個 master
程式和多個 worker
程式。
master
程式
master程式主要用來管理worker程式,master的工作:接收來自外界的訊號,向各worker程式傳送訊號,監控worker程式的執行狀態,當worker程式退出後(異常關閉下),重新開啟新的worker程式。
master 程式主要完成如下工作:
讀取並驗證配置資訊
建立、繫結及關閉套接字
啟動、終止worker程式及維護worker程式的個數
無須終止服務而重新配置工作
控制非中斷式程式升級、啟用新的二進位制程式及在有需要時回滾至老版本
重新開啟日誌檔案
編譯嵌入式Perl指令碼
worker
程式
對於基本的網路請求,Nginx則是放在worker程式來處理。多個worker程式之間是對等的,他們同等競爭來自客戶端的請求,各程式之間相互獨立。
一個請求,只能在一個worker程式中處理, 一個worker程式,不可能處理其它程式的請求。之間的關係是一對一。
Nginx在啟動時,建立一組初始的監聽套接字,HTTP 請求和響應之時,worker 連續接收、讀取和寫入套接字。
worker 程式主要完成如下工作:
- 接收、傳入並處理來自客戶端的請求
- 提供反向代理及過濾功能
- nginx任何能完成的其他任務
既然 worker 程式之間是平等的,每個程式,處理請求的機會也是一樣的。當我們提供 80
埠的 http
服務時,一個連線請求過來,每個程式都有可能處理這個連線。那麼問題來了,到底最後怎樣處理,是由什麼決定的呢?我們來看一看一個完整的請求是怎樣通過互相的協作來實現的:
- 首先,每個 worker 程式都是從 master 程式
fork
過來,在 master 程式裡面,先建立好需要listen
的socket
(listenfd
)之後,然後再fork
出多個 worker 程式。 - 所有 worker 程式的
listenfd
會在新連線到來時變得可讀,為保證只有一個程式處理該連線,所有 worker 程式會在註冊listenfd
讀事件前搶accept_mutex
,搶到互斥鎖的那個程式註冊listenfd
讀事件,然後在讀事件裡呼叫accept
接受該連線。 - 當一個 worker 程式在
accept
這個連線之後,就開始讀取請求、解析請求、處理請求。產生資料後,再返回給客戶端,最後才斷開連線,這樣一個完整的請求就是這樣的了。
我們可以看到:一個請求,完全由 worker 程式來處理,而且只在一個 worker 程式中處理。
本作品採用《CC 協議》,轉載必須註明作者和本文連結