浅谈Nginx服务器的内部核心架构设计
前言
Nginx 是一個 免費的,開源的,高性能 的 HTTP 服務器和 反向代理,以及 IMAP / POP3 代理服務器。 Nginx 以其高性能,穩定性,豐富的功能,簡單的配置和低資源消耗而聞名。Nginx是一個 Web 服務器,也可以用作 反向代理,負載均衡器 和 HTTP 緩存。
很多高知名度的網站都使用 Nginx,如:Netflix,GitHub,SoundCloud,MaxCDN 等。
?
?
?
正文
1. 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 服務器被分解為 多個模塊,每個模塊就是一個 功能模塊,只負責自身的功能,模塊之間嚴格遵循 “高內聚,低耦合” 的原則。
?
?
?
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 的 事件驅動模型 由 事件收集器、事件發送器 和 事件處理器 三部分基本單元組成。
-
事件收集器:負責收集 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 服務器的運行過程中,主進程 和 工作進程 需要進程交互。交互依賴于 Socket 實現的 管道 來實現。
5.1. 主進程與工作進程交互
這條管道與普通的管道不同,它是由 主進程 指向 工作進程 的 單向管道,包含主進程向工作進程發出的 指令,工作進程 ID 等;同時 主進程 與外界通過 信號通信;每個 子進程 具備 接收信號,并處理相應的事件的能力。
5.2. 工作進程與工作進程交互
這種交互是和 主進程-工作進程 交互是基本一致的,但是會通過 主進程 間接完成。工作進程 之間是 相互隔離 的,所以當工作進程 W1 需要向工作進程 W2 發指令時,首先找到 W2 的 進程 ID,然后將正確的指令寫入指向 W2 的 通道。W2 收到信號采取相應的措施。
小結
通過這篇文章,我們對 Nginx 服務器的 整體架構 有了一個整體的認識。包括其 模塊化的設計、多進程 和 異步非阻塞 的請求處理方式、事件驅動模型 等。通過這些理論知識,才能更好地領悟 Nginx 的設計思想。對于我們學習 Nginx 來說有很大的幫助。
作者:零壹技術棧
鏈接:https://juejin.im/post/5b4bdb54e51d45191e0cd774
來源:掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
來源:https://juejin.im/post/5b4bdb54e51d45191e0cd774
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的浅谈Nginx服务器的内部核心架构设计的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 就业协议中的入伍包含军队文职录用吗
- 下一篇: CentOS7中使用yum安装Nginx