Nginx 原理
Nginx 以其高性能,穩定性,豐富的功能,簡單的配置和低資源消耗而聞名。
Nginx進程模型
Nginx 是一個多進程的模型,主要分為一個 Master 進程、多個 Worker 進程。
-
Master 進程: 管理 Worker 進程。
-
對外接口:接收外部的操作(信號);
-
對內轉發:根據外部的操作的不同,通過信號管理 Worker;
-
監控:監控 Worker 進程的運行狀態,Worker 進程異常終止后,自動重啟 Worker 進程。
-
-
Worker 進程: 所有 Worker 進程都是平等的。
-
實際處理:網絡請求,由 Worker 進程處理。
-
Worker 進程數量:在 nginx.conf 中配置,一般設置為核心數,充分利用 CPU 資源,同時,避免進程數量過多,避免進程競爭 CPU 資源,增加上下文切換的損耗。
-
HTTP 連接建立和請求處理過程
-
Nginx 啟動時,Master 進程,加載配置文件。
-
Master 進程,初始化監聽的 Socket。
-
Master 進程,Fork 出多個 Worker 進程。
-
Worker 進程,競爭新的連接,獲勝方通過三次握手,建立 Socket 連接,並處理請求。
Nginx 高性能、高並發
Nginx 為什么擁有高性能並且能夠支撐高並發?
-
Nginx 采用多進程 + 異步非阻塞方式(IO 多路復用 Epoll)。
-
請求的完整過程:建立連接→讀取請求→解析請求→處理請求→響應請求。
-
請求的完整過程對應到底層就是:讀寫 Socket 事件。
Nginx 的事件處理模型
Request:Nginx 中 HTTP 請求。
基本的 HTTP Web Server 工作模式:
-
接收請求: 逐行讀取請求行和請求頭,判斷段有請求體后,讀取請求體。
-
處理請求。
-
返回響應: 根據處理結果,生成相應的 HTTP 請求(響應行、響應頭、響應體)。
模塊化體系結構
nginx的模塊根據其功能基本上可以分為以下幾種類型:
- event module: 搭建了獨立於操作系統的事件處理機制的框架,及提供了各具體事件的處理。包括ngx_events_module, ngx_event_core_module和ngx_epoll_module等。nginx具體使用何種事件處理模塊,這依賴於具體的操作系統和編譯選項。
- phase handler: 此類型的模塊也被直接稱為handler模塊。主要負責處理客戶端請求並產生待響應內容,比如ngx_http_static_module模塊,負責客戶端的靜態頁面請求處理並將對應的磁盤文件准備為響應內容輸出。
- output filter: 也稱為filter模塊,主要是負責對輸出的內容進行處理,可以對輸出進行修改。例如,可以實現對輸出的所有html頁面增加預定義的footbar一類的工作,或者對輸出的圖片的URL進行替換之類的工作。
- upstream: upstream模塊實現反向代理的功能,將真正的請求轉發到后端服務器上,並從后端服務器上讀取響應,發回客戶端。upstream模塊是一種特殊的handler,只不過響應內容不是真正由自己產生的,而是從后端服務器上讀取的。
- load-balancer: 負載均衡模塊,實現特定的算法,在眾多的后端服務器中,選擇一個服務器出來作為某個請求的轉發服務器。
基礎背景:
- Nginx 是多進程模型,Worker 進程用於處理請求;
- 單個進程的連接數(文件描述符 fd),有上限(
nofile
):ulimit -n
- Nginx 上配置單個 worker 進程的最大連接數:
worker_connections
上限為nofile
- Nginx 上配置 worker 進程的數量:
worker_processes
因此,Nginx 的最大連接數:
- Nginx 的最大連接數:
Worker 進程數量
x單個 Worker 進程的最大連接數
- 上面是 Nginx 作為通用服務器時,最大的連接數
- Nginx 作為
反向代理
服務器時,能夠服務的最大連接數:(Worker 進程數量
x單個 Worker 進程的最大連接數
)/ 2。 - Nginx 反向代理時,會建立
Client 的連接
和后端 Web Server 的連接
,占用 2 個連接
Nginx vs. Apache
以下內容來源於:http://www.oschina.net/translate/nginx-vs-apache
what's the Apache
Apache 服務器從 1995 年就開始使用了。相比其他產品,Apache 服務器是使用最多的,其次是微軟的 IIS 服務器。
由於開源的 Apache 服務器已經被使用多年,並且有眾多的用戶,人們開發出了很多的模塊來擴展它的功能,其中的大多數模塊也是開源的。舉例來說,一個比較常見的配置是使用 Apache 來為靜態頁面提供服務,並使用 mod_jk 模塊來運行 Tomcat 上的 Java 和 JSP 代碼,以便使程序具有交互功能。另一個例子是使用 mod_php 模塊來執行 php 代碼,而不用去使用 cgi。
但是,Apache 在高負載的情況下表現的差強人意,原因是它需要去運行新的進程,因此要消耗更多的內存。同時,他還要產生新的線程來與其他的線程競爭內存和 CPU。當進程的流量達到了管理員設置的上限時,Apache 會拒絕新的連接。
what's the Nginx
Nginx 是一個開源的服務器,用來解決一些 Apache 在性能和擴展性方面的問題的。Nginx 是開源並且免費的,但是如果你購買了它的 Nginx Plus 版本的話是可以享受到服務支持的。
Nginx 聲稱它的服務器是用來解決 C10K 問題(出自Daniel Kegel發表的一篇關於如何使一個服務器處理10000個連接——假設的操作系統的上限的論文)的。在他的論文中,他引用了另一篇由 Dean Gaudet 寫的論文,其中寫到“你們為什么不使用一個像 Zeus 那樣的選擇/事件(select/event)為基礎的模型呢?很明顯那是最快的”。
Nginx 確實是以事件為基礎的(event-based)。他們把他們的架構稱為“事件驅動且異步”(event-driven and asynchronous)。Apache 依賴於進程和線程。那么,區別是什么呢?
Apache 的工作方式
Apache 通過創建進程和線程來處理其他的連接。管理員可以通過設置來控制服務器所能允許的最大進程數量。這個配置因機器的可用內存而異。過多的進程會耗盡內存從而使得機器使用磁盤上的交換內存,這嚴重的降低了性能。而且,當達到進程的上限之后,Apache 會拒絕新的連接。
Apache 可以通過設置來運行在 pre-forked 模式或 worker multi-process 模式(MPM)。當其他的用戶連接時,兩種方式都會創建新的進程。區別在於,pre-forked 模式為每一個進程創建一個線程,用來處理一個用戶的請求。worker 模式也創建新的進程,但是每一個進程至少有一個線程,每一個線程用來處理單個用戶的單個請求。所以,一個 worker mode 的進程處理至少一個連接,而一個 per-fork 模式的進程只處理一個連接。
相比於 forked 模式,worker 模式使用更少的內存,原因是進程比線程消耗更多的內存,線程只是運行在進程中的代碼。
此外,worker 模式不是線程安全的。這意味着如果你使用像 mod_php 這樣的非線程安全的模塊來服務 php 頁面時,你需要使用 pre-forked 模式,因此要消耗更多的內存。所以,當選擇模塊和配置服務器時,你必須要面對是線程還是進程更優的問題以及一些約束的問題。
在調整 Apache 時的一個限制因素是內存以及當爭奪同一個CPU和內存時潛在的線程死鎖問題。如果一個線程停止了,用戶會一直處於等待頁面出現的狀態,直到進程將該線程回收,以便可以發回頁面。如果一個線程發生了死鎖,它不知道如何重啟,因此會一直處於卡住狀態。
Nginx 的工作方式
和 Apache 相比,Nginx 的工作方式有很大不同,主要是在於它如何處理線程。
Nginx 並不會為每一個的 web 請求創建新的進程,相反,管理員可以配置 Nginx 主進程的工作進程的數量(一個常見的做法是為每一個 CPU 配置一個工作進程)。所有這些進程都是單線程的。每一個工作進程可以處理數千個並發的請求。它通過一個線程來異步的完成了這些工作,而沒有使用多線程的編程模型。
Nginx 還拆分了緩存加載器(cache loader)和緩存管理器(cache manager)進程用來從磁盤中讀取數據並將其加載到緩存中,當緩存直接讀取的時候緩存過期。
Nginx 有一系列的模塊組成,這些模塊在編譯的時候就被包含進去了。這意味着,用戶下載源碼並選擇他們要編譯的模塊。這些模塊中包括連接后端應用服務器,負載均衡,代理服務器以及其他。並沒有 PHP 的模塊,因為 Nginx可 以自己編譯 PHP 代碼。
下圖為 Nginx 的架構
從這個圖表中我們可以看出,Nginx 使用 FastCGI 進程來執行 Python,Ruby 以及其他代碼,使用 Memcached 對象緩存系統。工作進程為 HTTP 請求加載 ht_core Nginx 進程。我們還可以看到,Nginx 和 Windows 以及 Linux 內核的功能緊密的集成在了一起,以便提升性能。這些內核功能已經經過長時間的改良,而 Nginx 正是利用了這一點。
Nginx 聲稱是事件驅動,異步且無阻塞的。“事件(Event)”指的是一個用戶的連接。“異步(Asynchronous)”指的是它一次處理多個用戶連接的用戶交互。“無阻塞(Non-blocking)”指的是它不會由於 CPU 處於忙狀態而停止磁盤的 I/O,在這種情況下,它會處理其他事件,直到 I/O 資源得到釋放。
網絡 IO 模型:
- nginx:IO 多路復用,epoll(freebsd 上是 kqueue )
- 高性能
- 高並發
- 占用系統資源少
- apache:阻塞 + 多進程/多線程
- 更穩定,bug 少
- 模塊更豐富
參考:https://www.zhihu.com/question/19571087
IO 多路復用
:單個連接的請求處理速度沒有優勢,適合 IO 密集型 場景,事件驅動- 大並發量:只使用一個線程,處理大量的並發請求,降低上下文環境切換損耗,也不需要考慮並發問題,相對可以處理更多的請求;
- 消耗更少的系統資源(不需要
線程調度開銷
) - 適用於
長連接
的情況(多線程模式長連接
容易造成線程過多
,造成頻繁調度
)
阻塞IO
+多線程
:實現簡單,可以不依賴系統調用,適合 CPU 密集型 場景- 每個線程,都需要時間和空間;
- 線程數量增長時,線程調度開銷指數增長
其他鏈接