Nginx
是一個 免費的,開源的,高性能 的 HTTP
服務器和 反向代理,以及 IMAP
/ POP3
代理服務器。 Nginx
以其高性能,穩定性,豐富的功能,簡單的配置和低資源消耗而聞名。Nginx
是一個 Web
服務器,也能夠用做 反向代理,負載均衡器 和 HTTP
緩存。編程
不少高知名度的網站都使用 Nginx
,如:Netflix
,GitHub
,SoundCloud
,MaxCDN
等。windows
Nginx
啓動時,會生成兩種類型的 進程*,一個是 主進程(master
),一個(windows
版本的目前只有一個)或 多個工做進程(worker
)。主進程 並不處理網絡請求,主要負責 調度工做進程,也就是圖示的 3
項:加載配置、啓動工做進程 及 非停升級。因此,Nginx
啓動之後,查看操做系統的進程列表,咱們就能看到 至少有兩個 Nginx
進程。後端
服務器實際 處理網絡請求 及 響應 的是 工做進程(worker
),在類 unix
系統上,Nginx
能夠配置 多個 worker
,而每一個 worker
進程 均可以同時處理 數以千計 的 網絡請求。緩存
Nginx
的 worker
進程,包括 核心 和 功能性模塊,核心模塊 負責維持一個 運行循環(run-loop
),執行網絡請求處理的 不一樣階段 的模塊功能,好比:網絡讀寫、存儲讀寫、內容傳輸、外出過濾,以及 將請求發往上游服務器 等。而其代碼的 模塊化設計,也使得咱們能夠根據須要對 功能模塊 進行適當的 選擇 和 修改,編譯成具備 特定功能 的服務器。安全
基於 異步及非阻塞 的 事件驅動模型,能夠說是 Nginx
得以得到 高併發、高性能 的關鍵因素,同時也得益於對 Linux
、Solaris
及類 BSD
等操做系統內核中 事件通知 及 I/O
性能加強功能 的採用,如 kqueue
、epoll
及 event ports
。服務器
代理設計,能夠說是 Nginx
深刻骨髓的設計,不管是對於 HTTP
,仍是對於 FastCGI
、Memcache
、Redis
等的網絡請求或響應,本質上都採用了 代理機制。因此,Nginx
天生就是高性能的 代理服務器。網絡
高度模塊化 的設計是 Nginx
的架構基礎。Nginx
服務器被分解爲 多個模塊,每一個模塊就是一個 功能模塊,只負責自身的功能,模塊之間嚴格遵循 「高內聚,低耦合」 的原則。多線程
核心模塊 是 Nginx
服務器正常運行 必不可少 的模塊,提供 錯誤日誌記錄、配置文件解析、事件驅動機制、進程管理 等核心功能。架構
標準 HTTP
模塊提供 HTTP
協議解析相關的功能,好比:端口配置、網頁編碼設置、HTTP
響應頭設置 等等。併發
可選 HTTP
模塊主要用於 擴展 標準的 HTTP
功能,讓 Nginx
能處理一些特殊的服務,好比:Flash
多媒體傳輸、解析 GeoIP
請求、網絡傳輸壓縮、安全協議 SSL
支持等。
郵件服務模塊 主要用於支持 Nginx
的 郵件服務,包括對 POP3
協議、IMAP
協議和 SMTP
協議的支持。
第三方模塊 是爲了擴展 Nginx
服務器應用,完成開發者自定義功能,好比:Json
支持、Lua
支持等。
Nginx
是一個 高性能 的 Web
服務器,可以同時處理 大量的併發請求。它結合 多進程機制 和 異步機制,異步機制使用的是 異步非阻塞方式,接下來就給你們介紹一下 Nginx
的 多線程機制 和 異步非阻塞機制。
服務器每當收到一個客戶端時,就有 服務器主進程(master process
)生成一個 子進程(worker process
)出來和客戶端創建鏈接進行交互,直到鏈接斷開,該子進程就結束了。
使用 進程 的好處是 各個進程之間相互獨立,不須要加鎖,減小了使用鎖對性能形成影響,同時下降編程的複雜度,下降開發成本。其次,採用獨立的進程,可讓 進程互相之間不會影響,若是一個進程發生異常退出時,其它進程正常工做,master
進程則很快啓動新的 worker
進程,確保服務不會中斷,從而將風險降到最低。
缺點是操做系統生成一個 子進程 須要進行 內存複製 等操做,在 資源 和 時間 上會產生必定的開銷。當有 大量請求 時,會致使 系統性能降低。
每一個 工做進程 使用 異步非阻塞方式,能夠處理 多個客戶端請求。
當某個 工做進程 接收到客戶端的請求之後,調用 IO
進行處理,若是不能當即獲得結果,就去 處理其餘請求(即爲 非阻塞);而 客戶端 在此期間也 無需等待響應,能夠去處理其餘事情(即爲 異步)。
當 IO
返回時,就會通知此 工做進程;該進程獲得通知,暫時 掛起 當前處理的事務去 響應客戶端請求。
在 Nginx
的 異步非阻塞機制 中,工做進程 在調用 IO
後,就去處理其餘的請求,當 IO
調用返回後,會 通知 該 工做進程。對於這樣的系統調用,主要使用 Nginx
服務器的 事件驅動模型 來實現。
如上圖所示,Nginx
的 事件驅動模型 由 事件收集器、事件發送器 和 事件處理器 三部分基本單元組成。
事件收集器:負責收集 worker
進程的各類 IO
請求;
事件發送器:負責將 IO
事件發送到 事件處理器;
事件處理器:負責各類事件的 響應工做。
事件發送器 將每一個請求放入一個 待處理事件列表,使用非阻塞 I/O
方式調用 事件處理器 來處理該請求。其處理方式稱爲 「多路 IO 複用方法」,常見的包括如下三種:select
模型、poll
模型、epoll
模型。
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
實現的 管道 來實現。
這條管道與普通的管道不一樣,它是由 主進程 指向 工做進程 的 單向管道,包含主進程向工做進程發出的 指令,工做進程 ID
等;同時 主進程 與外界經過 信號通訊;每一個 子進程 具有 接收信號,並處理相應的事件的能力。
這種交互是和 主進程-工做進程 交互是基本一致的,可是會經過 主進程 間接完成。工做進程 之間是 相互隔離 的,因此當工做進程 W1
須要向工做進程 W2
發指令時,首先找到 W2
的 進程 ID
,而後將正確的指令寫入指向 W2
的 通道。W2
收到信號採起相應的措施。
經過這篇文章,咱們對 Nginx
服務器的 總體架構 有了一個總體的認識。包括其 模塊化的設計、多進程 和 異步非阻塞 的請求處理方式、事件驅動模型 等。經過這些理論知識,才能更好地領悟 Nginx
的設計思想。對於咱們學習 Nginx
來講有很大的幫助。
歡迎關注技術公衆號: 零壹技術棧
本賬號將持續分享後端技術乾貨,包括虛擬機基礎,多線程編程,高性能框架,異步、緩存和消息中間件,分佈式和微服務,架構學習和進階等學習資料和文章。