Nginx---Ngine X,是一款免費的、自由的、開源的、高性能HTTP服務器和反向代理服務器;也是一個IMAP、POP3、SMTP代理服務器;Nginx以其高性能、穩定性、豐富的功能、簡單的配置和低資源消耗而聞名。
也就是說Nginx本身就可以托管網站(類似于Tomcat一樣),進行Http服務處理,也可以作為反向代理服務器 、負載均衡器和HTTP緩存。
Nginx 解決了服務器的C10K(就是在一秒之內連接客戶端的數目為10k即1萬)問題。它的設計不像傳統的服務器那樣使用線程處理請求,而是一個更加高級的機制—事件驅動機制,是一種異步事件驅動結構。
- 跨平臺:可以在大多數Unix like 系統編譯運行。而且也有Windows的移植版本。
- 配置異常簡單:非常的簡單,易上手。
- 非阻塞、高并發連接:數據復制時,磁盤I/O的第一階段是非阻塞的。官方測試能支持5萬并發連接,實際生產中能跑2~3萬并發連接數(得益于Nginx采用了最新的epoll事件處理模型(消息隊列)。
- Nginx代理和后端Web服務器間無需長連接;
- Nginx接收用戶請求是異步的,即先將用戶請求全部接收下來,再一次性發送到后端Web服務器,極大減輕后端Web服務器的壓力。
- 發送響應報文時,是邊接收來自后端Web服務器的數據,邊發送給客戶端。
- 網絡依賴性低,理論上只要能夠ping通就可以實施負載均衡,而且可以有效區分內網、外網流量。
- 支持內置服務器檢測。Nginx能夠根據應用服務器處理頁面返回的狀態碼、超時信息等檢測服務器是否出現故障,并及時返回錯誤的請求重新提交到其它節點上。
- 此外還有內存消耗小、成本低廉(比F5硬件負載均衡器廉價太多)、節省帶寬、穩定性高等特點。
三、Nginx的整體架構
1、模塊化設計
Nginx 的Worker 進程,包括核心和功能性模塊 ,核心模塊負責維持一個運行循環( run-loop ),執行網絡請求處理的不同階段的模塊功能,比如:存儲讀寫、內容傳輸 、網絡讀寫 、外出過濾 ,以及將請求發往上游服務器等。而其代碼的模塊化設計 ,也使得我們可以根據需要對功能模塊進行適當的選擇和修改 ,編譯成具有特定功能的服務器。
2、代理設計
代理(proxy)設計,可以說是 Nginx 深入骨髓的設計,無論是對于HTTP,還是對于Memcache 、Redis、FastCGI 等的網絡請求或響應,本質上都采用了代理機制 。所以,Nginx 天生就是高性能的代理服務器 。
3、事件驅動模型
基于異步及非阻塞的事件驅動模型 ,可以說是 Nginx 得以獲得 高并發 、 高性能 的關鍵因素,同時也得益于對 Linux 、 Solaris 及類 BSD 等操作系統內核中 事件通知 及 I/O 性能增強功能 的采用,如kqueue 、 epoll 及 event ports 。
4、主進程模型
Nginx 啟動時,會生成兩種類型的進程,一個是主進程 ( Master ), 一個或多個工作進程 ( Worker )。主進程并不處理網絡請求,主要負責調度工作進程 ,也就是圖示的3項:加載配置 、 啟動工作進程及非停升級。所以Nginx啟動以后,查看操作系統的進程列表,我們就能看到至少有兩個Nginx進程。
5、工作進程模型
服務器實際處理網絡請求及響應的是工作進程,在類Unix 系統上,Nginx可以配置多個Worker ,而每個Worker 進程都可以同時處理數以千計的網絡請求。
四、Nginx的模塊化設計
高度模塊化的設計是 Nginx 的架構基礎。Nginx 服務器被分解為多個模塊 ,每個模塊就是一個功能模塊 ,只負責自身的功能,模塊之間嚴格遵循 “高內聚,低耦合” 的原則。
1、核心模塊
核心模塊是 Nginx 服務器正常運行必不可少的模塊,提供錯誤日志記錄 、配置文件解析、事件驅動機制、進程管理等核心功能。
2、標準HTTP模塊
標準 HTTP 模塊提供 HTTP 協議解析相關的功能,比如: 端口配置 、 網頁編碼設置 、 HTTP響應頭設置 等等。
3、可選HTTP模塊
可選 HTTP 模塊主要用于 擴展 標準的 HTTP 功能,讓 Nginx 能處理一些特殊的服務,比如:Flash 多媒體傳輸 、解析 GeoIP 請求、 網絡傳輸壓縮 、 安全協議 SSL 支持等。
4、郵件服務模塊
郵件服務模塊主要用于支持 Nginx 的 郵件服務 ,包括對 POP3 協議、 IMAP 協議和 SMTP協議的支持。
5、第三方模塊
第三方模塊是為了擴展 Nginx 服務器應用,完成開發者自定義功能,比如:Json 支持、 Lua 支持等。
五、代理設計中的正向代理和反向代理
首先,代理服務器一般指局域網內部的機器通過代理服務器發送請求到互聯網上的服務器,代理服務器一般作用在客戶端。例如:GoAgent翻墻軟件。我們的客戶端在進行翻墻操作的時候,我們使用的正是正向代理,通過正向代理的方式,在我們的客戶端運行一個軟件,將我們的HTTP請求轉發到其他不同的服務器端,實現請求的分發。
反向代理服務器作用在服務器端,它在服務器端接收客戶端的請求,然后將請求分發給具體的服務器進行處理,然后再將服務器的相應結果反饋給客戶端。Nginx就是一個反向代理服務器軟件。
從上圖可以看出:客戶端必須設置正向代理服務器,當然前提是要知道正向代理服務器的IP地址,還有代理程序的端口。
反向代理正好與正向代理相反,對于客戶端而言代理服務器就像是原始服務器,并且客戶端不需要進行任何特別的設置??蛻舳讼蚍聪虼淼拿臻g(name-space)中的內容發送普通請求,接著反向代理將判斷向何處(原始服務器)轉交請求,并將獲得的內容返回給客戶端。
六、Nginx事件驅動模型
在 Nginx 的異步非阻塞機制中,工作進程在調用 IO 后,就去處理其他的請求,當 IO 調用返回后,會通知該工作進程 。對于這樣的系統調用,主要使用 Nginx 服務器的事件驅動模型來實現。
如上圖所示, Nginx 的 事件驅動模型由事件發送器、事件收集器和事件處理器三部分基本單元組成:
- 事件發送器:負責將 IO 事件發送到事件處理器 ;
- 事件收集器:負責收集Worker 進程的各種 IO 請求;
- 事件處理器:負責各種事件的響應工作 。
事件發送器將每個請求放入一個 待處理事件列表 ,使用非阻塞 I/O 方式調用 事件處理器來處理該請求。其處理方式稱為 “多路 IO 復用方法” ,常見的包括以下三種:select 模型、 poll模型、 epoll 模型。
七、Nginx的請求方式處理
Nginx 是一個高性能的 Web 服務器,能夠同時處理大量的并發請求。它結合多進程機制和異步機制 ,異步機制使用的是異步非阻塞方式 ,接下來就給大家介紹一下 Nginx 的多線程機制和異步非阻塞機制 。
1、多進程機制
服務器每當收到一個客戶端時,就有 服務器主進程 ( master process )生成一個 子進程( worker process )出來和客戶端建立連接進行交互,直到連接斷開,該子進程就結束了。
使用進程的好處是各個進程之間相互獨立,不需要加鎖,減少了使用鎖對性能造成影響,同時降低編程的復雜度,降低開發成本。其次,采用獨立的進程,可以讓進程互相之間不會影響 ,如果一個進程發生異常退出時,其它進程正常工作, master 進程則很快啟動新的 worker 進程,確保服務不會中斷,從而將風險降到最低。
缺點是操作系統生成一個子進程需要進行 內存復制等操作,在資源和時間上會產生一定的開銷。當有大量請求時,會導致系統性能下降 。
2、異步非阻塞機制
每個工作進程 使用 異步非阻塞方式 ,可以處理 多個客戶端請求 。
當某個 工作進程 接收到客戶端的請求以后,調用 IO 進行處理,如果不能立即得到結果,就去 處理其他請求 (即為 非阻塞 );而 客戶端 在此期間也 無需等待響應 ,可以去處理其他事情(即為 異步 )。
當 IO 返回時,就會通知此 工作進程 ;該進程得到通知,暫時 掛起 當前處理的事務去 響應客戶端請求 。
八、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 實現的管道來實現。
1、主進程與工作進程交互
這條管道與普通的管道不同,它是由主進程指向工作進程的單向管道,包含主進程向工作進程發出的指令,工作進程 ID 等;同時主進程與外界通過信號通信;每個 子進程具備接收信號,并處理相應的事件的能力。
2、工作進程與工作進程交互
這種交互是和主進程-工作進程交互是基本一致的,但是會通過主進程間接完成。 工作進程之間是相互隔離的,所以當工作進程 W1 需要向工作進程 W2 發指令時,首先找到 W2 的 進程ID,然后將正確的指令寫入指向 W2 的 通道。W2 收到信號采取相應的措施。
九、小結
通過這篇文章,我們對 Nginx 服務器的整體架構有了一個整體的認識。包括其模塊化的設計、多進程和異步非阻塞的請求處理方式、事件驅動模型等。通過這些理論知識,才能更好地領悟 Nginx 的設計思想。對于我們學習 Nginx 來說有很大的幫助。
掃碼二維碼 獲取免費視頻學習資料
- 本文固定鏈接: http://www.wangchenghua.com/post/7302/
- 轉載請注明:轉載必須在正文中標注并保留原文鏈接
- 掃碼: 掃上方二維碼獲取免費視頻資料