nginx為什麼性能這麼優越?

趙彬衫


看到下面回答中“nginx是基於epoll模型開發的,而epoll是基於JAVA NIO的同步非阻塞開發“,忍不住想這回答還真是無畏啊,錯的離譜,竟還有那麼多點贊。應該說Epoll機制僅僅是nginx在Linux上實現事件驅動的一種技術而已,說nginx基於epoll開發那就錯了,說nginx基於java nio開發就更不知所云了。

當我們說性能優越的時候,我們在說什麼呢?首先讓我們看看有哪些衡量性能的性能指標吧。

性能指標一般包括響應時間、吞吐量、併發用戶數等。

響應時間指功能完成的時間,和客觀環境、數據量級、主觀感受等都有關係。客觀環境中硬件包括服務器配置、客戶端機器配置等,軟件包括數據庫部署方式、客戶端使用的瀏覽器等,另外還有網絡環境。

吞吐量是給定時間內系統可處理的事務/請求的數量等,例如網絡傳輸的數據流量。這個指標對於互聯網軟件更為關鍵,目前我們尚未進行定量分析和測試。

併發用戶數用來衡量系統的同步協調能力,我們更關注多個用戶同時操作同一功能或數據時,對系統性能的影響。

總的來說,nginx的性能是指其低延遲、高吞吐、高併發能力。

下面我們就從架構設計的角度,來分析nginx是如何做到低延遲、高吞吐、高併發能力的。

Nginx採用一個Master管理進程,多個worker工作進程的設計方式。如下圖所示,Master進程管理了完全相同的worker進程,一個cache manager進程和cache loader進程。

這種多進程的架構可以充分利用多核系統的併發處理能力。同時,多個worker進程間可以實現負載均衡,一個請求到來時更容易被分配到負載較輕的worker進程中處理。這將降低請求的延遲,也提高了網絡處理的性能。

Nginx進程內部採用了非阻塞方式的事件驅動架構模式,這也是Nginx不同於傳統Web服務器的地方。傳統的Web服務器而言,採用的所謂事件驅動往往侷限於TCP建立連接、關閉事件上,一個連接建立以後,在關閉之前的所有操作都不再是事件驅動,這時會退化成按序執行每個操作的批處理模式,這樣每個請求在連接建立之後都將始終佔用系統資源,直到關閉才會釋放。

nginx的異步事件驅動實際上是請求的多階段異步處理的過程。nginx實際把請求處理流程劃分為了11個階段,這樣劃分的原因是將請求的執行邏輯細分,各階段按照處理時機定義了清晰的執行語義,開發者可以很容易分辨自己需要開發的模塊應該定義在什麼階段。

nginx做為一個異步高效的事件驅動型web服務器,在linux平臺中當系統支持epoll時nginx默認採用epoll來高效的處理事件。Epoll實際上是 poll 的一種改進,它可以處理大批量的句柄。而 poll 又是select 的一種改進。在select 中對所打開的文件描述符個數有一定的限制,該限制由 FD_SETSIZE 設置(一般為 1024 或 2048), 而且內核中的 select 的實現是採用輪詢來處理描文件描述符集,因此效率低。當文件描述符集中的某個描述符處於可讀、可寫或異常狀態時,select 採用內存拷貝方法通知用戶空間。因此, 在select 模型中文件描述符個數受限且效率低的問題就很明顯。為了解決select 對文件描述符個數的限制,採用了 poll 模型,但是 poll 依然不能解決 select 的效率問題。所以,最終epoll 模型重新對poll 模型進行改進 。

epoll 的優點如下所示:

  • 處理大批量文件句柄:一個進程可以處理大批量的文件句柄,可處理文件描述符的個數遠大於 2048;


  • 高效率:內核實現中 epoll 是根據每個描述符上面的回調函數實現的,並且只有處於活動狀態的套接字才會主動調用該回調函數,其他不活動的套接字並不會去調用,因此,epoll 不必掃描整個文件描述符集,只需要掃描處於活動狀態的文件描述符。所有大大減低了效率。
  • 加快內核與用戶的消息傳遞:epoll 是通過內核與用戶空間mmap 同一塊內存實現內核與用戶之間消息的傳遞。
  • 內核微調:可以根據運行時所需內存動態調整內存大小。


Nginx的高性能有賴於其高效內存管理,下面我們看看其內存池設計。

Nginx 使用內存池對內存進行管理,把內存分配歸結為大內存分配和小內存分配。若申請的內存大小比同頁的內存池最大值 max 還大,則是大內存分配,否則為小內存分配。

  1. 大塊內存的分配請求不會直接在內存池上分配內存來滿足請求,而是直接向系統申請一塊內存(就像直接使用 malloc 分配內存一樣),然後將這塊內存掛到內存池頭部的 large 字段下。
  2. 小塊內存分配,則是從已有的內存池數據區中分配出一部分內存。

這樣設計的好處就是減少了內存碎片,提升了內存分配的效率。

總結一下,nginx優越的性能得益於其多進程、異步事件處理的架構,得益於其高效的內存管理。


本回答的內容參考了nginx官網上的內容,截圖也來自於https://www.nginx.com/blog/inside-nginx-how-we-designed-for-performance-scale/


坐雲觀潮


所謂沒有對比就沒有傷害!

在nginx橫空出世之前,Apache服務器一直佔據web服務器的壟斷地位,所以就用對比的方式來解釋nginx那麼強!

兩者性能差別的主要原因在於網絡IO模型選擇不同,apache使用了select,而nginx使用了epoll模型!

舉個例子:一個萬人村裡面選村長,有兩種方式:

①,讓每個人在紙條上寫下自己的名字,然後前村長去收集紙條(一個線程去遍歷),然後得到村長推薦候選人的名單(需要處理的連接),這就相當於select模型,去輪詢每一個連接,並對需要進行處理的連接進行處理!

②,每個人都可以毛遂自薦(每個連接都有可能活躍),想要競選的在旁邊站成一排(事件觸發,放入隊列中),然後就在這幾個人中選擇(幾個待處理的任務),相當於只要對少量的事件進行處理!

一個是從上萬人中循環得到幾個進行處理,一個是幾個自己站出來直接處理,這種效率相差不是一般的大吧?

nginx是基於epoll模型開發的,而epoll是基於JAVA NIO的同步非阻塞開發,在高併發情況下能支持更多的連接!

nginx是事件驅動的,一個主進程跟多個工作進程組成的工作模式,主線程負責循環分配事件,多個工作線程負責事件的處理!

我們通常使用nginx做什麼呢?

nginx作為高性能的http服務器和反向代理服務器,通常用做負載均衡組件,負責接受大量的連接然後基於一定的規則(輪詢,權重等)分發連接給不同的應用服務器進行處理!

而且負載均衡配置十分簡單,只需要在安裝好nginx之後,通過修改配置文件nginx.conf,將不同的連接分發到不同的服務器上(通過配置server),配置十分簡單!



一般來說,企業中使用nginx作為負載均衡組件的場景還是很多的,同時為了避免單點故障帶來的不穩定性,通常會使用keepalive搭建高可用的集群方案!

nginx搭建比較簡單,大家自己可以多玩一玩!更多的技術分享,敬請關注。。。


分享到:


相關文章: