淺談Nginx伺服器的內部核心架構設計

零壹技術棧發表於2018-07-15

前言

Nginx 是一個 免費的 , 開源的 , 高效能 的 HTTP 伺服器和 反向代理 ,以及 IMAP / POP3代理伺服器。 Nginx 以其高效能,穩定性,豐富的功能,簡單的配置和低資源消耗而聞名。 Nginx 是一個 Web 伺服器,也可以用作 反向代理 , 負載均衡器 和 HTTP 快取 。

很多高知名度的網站都使用 Nginx ,如: Netflix , GitHub , SoundCloud , MaxCDN 等。

淺談Nginx伺服器的內部核心架構設計

正文

1. Nginx的整體架構

淺談Nginx伺服器的內部核心架構設計

1.1. 主程式

Nginx 啟動時,會生成兩種型別的 程式 *,一個是 主程式 ( master ), 一個 ( windows版本的目前只有一個)或 多個工作程式 ( worker )。 主程式 並不處理網路請求,主要負責 排程工作程式 ,也就是圖示的 3 項: 載入配置 、 啟動工作程式 及 非停升級 。所以, Nginx 啟動以後,檢視作業系統的程式列表,我們就能看到 至少有兩個 Nginx 程式。

1.2. 工作程式

伺服器實際 處理網路請求 及 響應 的是 工作程式 ( worker ),在類 unix 系統上, Nginx可以配置 多個 worker ,而每個 worker 程式 都可以同時處理 數以千計 的 網路請求 。

1.3. 模組化設計

Nginx 的 worker 程式,包括 核心 和 功能性模組 , 核心模組 負責維持一個 執行迴圈 ( run-loop ),執行網路請求處理的 不同階段 的模組功能,比如: 網路讀寫 、 儲存讀寫 、 內容傳輸 、 外出過濾 ,以及 將請求發往上游伺服器 等。而其程式碼的 模組化設計 ,也使得我們可以根據需要對 功能模組 進行適當的 選擇 和 修改 ,編譯成具有 特定功能 的伺服器。

1.4. 事件驅動模型

基於 非同步及非阻塞 的 事件驅動模型 ,可以說是 Nginx 得以獲得 高併發 、 高效能 的關鍵因素,同時也得益於對 Linux 、 Solaris 及類 BSD 等作業系統核心中 事件通知 及 I/O 效能增強功能 的採用,如 kqueue 、 epoll 及 event ports 。

1.5. 代理(proxy)設計

代理設計,可以說是 Nginx 深入骨髓的設計,無論是對於 HTTP ,還是對於 FastCGI 、 Memcache 、 Redis 等的網路請求或響應,本質上都採用了 代理機制 。所以, Nginx 天生就是高效能的 代理伺服器 。

2. Nginx的模組化設計

高度模組化的設計是 Nginx 的架構基礎。 Nginx 伺服器被分解為 多個模組 ,每個模組就是一個 功能模組 ,只負責自身的功能,模組之間嚴格遵循 “高內聚,低耦合” 的原則。

淺談Nginx伺服器的內部核心架構設計

2.1. 核心模組

核心模組是 Nginx 伺服器正常執行 必不可少 的模組,提供 錯誤日誌記錄 、 配置檔案解析 、 事件驅動機制 、 程式管理 等核心功能。

2.2. 標準HTTP模組

標準 HTTP 模組提供 HTTP 協議解析相關的功能,比如: 埠配置 、 網頁編碼設定 、 HTTP響應頭設定 等等。

2.3. 可選HTTP模組

可選 HTTP 模組主要用於 擴充套件 標準的 HTTP 功能,讓 Nginx 能處理一些特殊的服務,比如: Flash 多媒體傳輸 、解析 GeoIP 請求、 網路傳輸壓縮 、 安全協議 SSL 支援等。

2.4. 郵件服務模組

郵件服務模組主要用於支援 Nginx 的 郵件服務 ,包括對 POP3 協議、 IMAP 協議和 SMTP協議的支援。

2.5. 第三方模組

第三方模組是為了擴充套件 Nginx 伺服器應用,完成開發者自定義功能,比如: Json 支援、 Lua 支援等。

3. Nginx的請求方式處理

Nginx 是一個 高效能 的 Web 伺服器,能夠同時處理 大量的併發請求 。它結合 多程式機制和 非同步機制 ,非同步機制使用的是 非同步非阻塞方式 ,接下來就給大家介紹一下 Nginx 的 多執行緒機制 和 非同步非阻塞機制 。

3.1. 多程式機制

伺服器每當收到一個客戶端時,就有 伺服器主程式 ( master process )生成一個 子程式( worker process )出來和客戶端建立連線進行互動,直到連線斷開,該子程式就結束了。

使用 程式 的好處是 各個程式之間相互獨立 , 不需要加鎖 ,減少了使用鎖對效能造成影響,同時降低程式設計的複雜度,降低開發成本。其次,採用獨立的程式,可以讓 程式互相之間不會影響 ,如果一個程式發生異常退出時,其它程式正常工作, master 程式則很快啟動新的 worker 程式,確保服務不會中斷,從而將風險降到最低。

缺點是作業系統生成一個 子程式 需要進行 記憶體複製 等操作,在 資源 和 時間 上會產生一定的開銷。當有 大量請求 時,會導致 系統效能下降 。

3.2. 非同步非阻塞機制

每個 工作程式 使用 非同步非阻塞方式 ,可以處理 多個客戶端請求 。

當某個 工作程式 接收到客戶端的請求以後,呼叫 IO 進行處理,如果不能立即得到結果,就去 處理其他請求 (即為 非阻塞 );而 客戶端 在此期間也 無需等待響應 ,可以去處理其他事情(即為 非同步 )。

當 IO 返回時,就會通知此 工作程式 ;該程式得到通知,暫時 掛起 當前處理的事務去 響應客戶端請求 。

4. Nginx事件驅動模型

在 Nginx 的 非同步非阻塞機制 中, 工作程式 在呼叫 IO 後,就去處理其他的請求,當 IO 呼叫返回後,會 通知 該 工作程式 。對於這樣的系統呼叫,主要使用 Nginx 伺服器的 事件驅動模型 來實現。

淺談Nginx伺服器的內部核心架構設計

如上圖所示, Nginx 的 事件驅動模型 由 事件收集器 、 事件傳送器 和 事件處理器 三部分基本單元組成。

  • 事件收集器:負責收集 worker 程式的各種 IO 請求;

  • 事件傳送器:負責將 IO 事件傳送到 事件處理器 ;

  • 事件處理器:負責各種事件的 響應工作 。

事件傳送器將每個請求放入一個 待處理事件列表 ,使用非阻塞 I/O 方式呼叫 事件處理器 來處理該請求。其處理方式稱為 “多路 IO 複用方法” ,常見的包括以下三種: select 模型、 poll模型、 epoll 模型。

5. Nginx程式處理模型

Nginx 伺服器使用 master/worker 多程式模式 。多執行緒啟動和執行的流程如下:

主程式 Master process 啟動後,通過一個 for 迴圈來 接收 和 處理外部訊號 ;

主程式通過 fork() 函式產生 worker 子程式 ,每個 子程式 執行一個 for 迴圈來實現 Nginx 伺服器 對事件的接收 和 處理 。

一般推薦 worker 程式數 與 CPU 核心數 一致,這樣一來不存在 大量的子程式 生成和管理任務,避免了程式之間 競爭 CPU 資源 和 程式切換 的開銷。而且 Nginx 為了更好的利用 多核特性 ,提供了 CPU 親緣性 的繫結選項,我們可以將某 一個程式繫結在某一個核 上,這樣就不會因為 程式的切換 帶來 Cache 的失效。

對於每個請求,有且只有一個 工作程式 對其處理。首先,每個 worker 程式都是從 master程式 fork 過來。在 master 程式裡面,先建立好需要 listen 的 socket(listenfd) 之後,然後再 fork 出多個 worker 程式。

所有 worker 程式的 listenfd 會在 新連線 到來時變得 可讀 ,為保證只有一個程式處理該連線,所有 worker 程式在註冊 listenfd 讀事件 前 搶佔 accept_mutex ,搶到 互斥鎖 的那個程式 註冊 listenfd 讀事件 ,在 讀事件 裡呼叫 accept 接受該連線。

當一個 worker 程式在 accept 這個連線之後,就開始 讀取請求 , 解析請求 , 處理請求 ,產生資料後,再 返回給客戶端 ,最後才 斷開連線 ,這樣一個完整的請求就是這樣的了。我們可以看到,一個請求,完全由 worker 程式來處理,而且只在一個 worker 程式中處理。

淺談Nginx伺服器的內部核心架構設計

在 Nginx 伺服器的執行過程中, 主程式 和 工作程式 需要程式互動。互動依賴於 Socket 實現的 管道 來實現。

5.1. 主程式與工作程式互動

這條管道與普通的管道不同,它是由 主程式 指向 工作程式 的 單向管道 ,包含主程式向工作程式發出的 指令 , 工作程式 ID 等;同時 主程式 與外界通過 訊號通訊 ;每個 子程式 具備 接收訊號 ,並處理相應的事件的能力。

5.2. 工作程式與工作程式互動

這種互動是和 主程式-工作程式 互動是基本一致的,但是會通過 主程式 間接完成。 工作程式之間是 相互隔離 的,所以當工作程式 W1 需要向工作程式 W2 發指令時,首先找到 W2 的 程式ID ,然後將正確的指令寫入指向 W2 的 通道 。 W2 收到訊號採取相應的措施。

小結

通過這篇文章,我們對 Nginx 伺服器的 整體架構 有了一個整體的認識。包括其 模組化的設計、 多程式 和 非同步非阻塞 的請求處理方式、 事件驅動模型 等。通過這些理論知識,才能更好地領悟 Nginx 的設計思想。對於我們學習 Nginx 來說有很大的幫助。

淺談Nginx伺服器的內部核心架構設計


相關文章