1. 程式人生 > >高效能Nginx介紹(一)

高效能Nginx介紹(一)

nginx(發音為“engine x”)是由俄羅斯軟體工程師Igor Sysoev編寫的免費開源Web伺服器。自2004年公開發布以來,nginx一直專注於高效能,高併發性和低記憶體使用。 Web伺服器功能之上的其他功能,如負載平衡,快取,訪問和頻寬控制,以及與各種應用程式高效整合的能力,有助於使nginx成為現代網站架構的良好選擇。目前,nginx是網際網路上第二大最受歡迎的開源Web伺服器。

14.1 為什麼高併發性很重要?

如今,網際網路如此廣泛和無處不在,很難想象它就像十年前我們所知道的那樣。從簡單的HTML生成可點選文字,基於NCSA,然後是Apache Web伺服器,到全球超過20億使用者使用的永遠線上的通訊媒體,它已經有了很大的發展。隨著永久連線的PC,移動裝置和最近的平板電腦的激增,網際網路格局正在迅速變化,整個經濟已經成為數字連線。線上服務變得更加精細,明顯偏向即時可用的實時資訊和娛樂。執行線上業務的安全方面也發生了重大變化。因此,網站現在比以前複雜得多,並且通常需要更多的工程努力才能具有健壯性和可擴充套件性。

網站架構師面臨的最大挑戰之一就是併發。自Web服務開始以來,併發性水平一直在不斷增長。一個流行的網站為數十萬甚至數百萬同時使用者提供服務的情況並不少見。十年前,併發的主要原因是緩慢的客戶端 - 具有ADSL或撥號連線的使用者。如今,併發性是由移動客戶端和較新的應用程式體系結構的組合引起的,這些體系結構通常基於維護持久連線,該連線允許客戶端使用新聞,推文,朋友訂閱源等進行更新。另一個有助於提高併發性的重要因素是現代瀏覽器的行為改變,它可以開啟四到六個同時連線到網站以提高頁面載入速度。

為了說明慢客戶端的問題,想象一個簡單的基於Apache的Web伺服器,它產生一個相對較短的100 KB響應 - 一個帶有文字或影象的網頁。生成或檢索此頁面只需幾分之一秒,但將其傳輸到頻寬為80 kbps(10 KB / s)的客戶端需要10秒鐘。從本質上講,Web伺服器會相對快速地提取100 KB的內容,然後在釋放連線之前,它會忙著將這些內容緩慢地傳送到客戶端10秒鐘。現在假設您有1,000個同時連線的客戶,他們請求了類似的內容。如果每個客戶端僅分配1 MB的額外記憶體,則會產生1000 MB(約1 GB)的額外記憶體,專門用於為1000個客戶端提供100 KB的內容。實際上,基於Apache的典型Web伺服器通常為每個連線分配超過1 MB的額外記憶體,令人遺憾的是,幾十kbps仍然是行動通訊的有效速度。雖然通過增加作業系統核心套接字緩衝區的大小,在某種程度上可以改善向慢速客戶端傳送內容的情況,但這不是解決該問題的一般方法,並且可能具有不良副作用。

對於持久連線,處理併發性的問題更加明顯,因為為了避免與建立新HTTP連線相關聯的延遲,客戶端將保持連線,並且對於每個連線的客戶端,Web伺服器分配了一定量的記憶體。

因此,為了處理與增長的受眾相關的增加的工作量以及因此更高的併發性 - 並且能夠持續這樣做 - 網站應該基於許多非常有效的構建塊。雖然硬體(CPU,記憶體,磁碟),網路容量,應用程式和資料儲存架構等方程式的其他部分顯然很重要,但是在Web伺服器軟體中,客戶端連線被接受和處理。因此,Web伺服器應該能夠隨著每秒同時連線和請求數量的增加而非線性地擴充套件

Apache不適合嗎?

Apache,這種網路伺服器軟體在很大程度上仍然主宰著網際網路,它的根源在於20世紀90年代初。最初,它的架構與當時存在的作業系統和硬體相匹配,但也與網際網路狀態相匹配,其中網站通常是執行單個Apache例項的獨立物理伺服器。到了2000年代初,很明顯,無法輕鬆複製獨立的Web伺服器模型以滿足不斷增長的Web服務的需求。儘管Apache為未來的開發提供了堅實的基礎,但它的架構是為每個新連線生成自己的副本,這不適合網站的非線性可伸縮性。最終,Apache成為了一個通用的Web伺服器,專注於擁有許多不同的功能,各種第三方擴充套件,以及幾乎任何型別的Web應用程式開發的普遍適用性。然而,沒有任何代價可以實現,並且在單個軟體中擁有如此豐富且通用的工具組合的缺點是可擴充套件性較低,因為每個連線的CPU和記憶體使用量增加。

因此,當伺服器硬體,作業系統和網路資源不再是網站增長的主要限制時,全球的Web開發人員開始尋找更有效的執行Web伺服器的方法。大約十年前,著名軟體工程師丹尼爾凱格爾宣稱“現在是網路伺服器同時處理一萬個客戶的時候了”,並預測了我們現在稱之為網際網路雲服務的東西。 Kegel的C10K清單激發了許多嘗試來解決Web伺服器優化問題,同時處理大量客戶端,nginx被證明是最成功的客戶之一。

旨在解決10,000個同時連線的C10K問題,nginx在編寫時考慮了不同的體系結構 - 一個更適合同時連線數和每秒請求數的非線性可伸縮性。 nginx是基於事件的,因此它不遵循Apache為每個網頁請求生成新程序或執行緒的風格。最終結果是,即使負載增加,記憶體和CPU使用率仍然可以管理。 nginx現在可以在具有典型硬體的伺服器上提供數萬個併發連線。

當nginx的第一個版本釋出時,它意味著與Apache一起部署,以便nginx處理靜態內容,如HTML,CSS,JavaScript和影象,以解除安裝基於Apache的應用程式伺服器的併發和延遲處理。在開發過程中,nginx通過使用FastCGI,uswgi或SCGI協議以及分散式記憶體物件快取系統(如memcached)增加了與應用程式的整合。還添加了其他有用的功能,例如具有負載平衡和快取的反向代理。這些附加功能使nginx成為有效的工具組合,可構建可擴充套件的Web基礎架構。

2012年2月,Apache 2.4.x分支機構向公眾釋出。儘管Apache的最新版本增加了新的多處理核心模組和旨在增強可擴充套件性和效能的新代理模組,但現在判斷它的效能,併發性和資源利用率是否與純事件相當或更好還為時尚早。驅動的Web伺服器。不過,看看Apache應用程式伺服器在新版本中的擴充套件效能會非常好,因為它可能會緩解後端方面的瓶頸,這在典型的nginx-plus-Apache Web配置中仍然沒有得到解決。

使用nginx有更多優勢嗎?

以高效能和高效率處理高併發性始終是部署nginx的關鍵優勢。但是,現在有更多有趣的好處。

在過去幾年中,Web架構師已經接受了將其應用程式基礎結構與Web伺服器分離和分離的想法。然而,以前以LAMP(Linux,Apache,MySQL,PHP,Python或Perl)為基礎的網站形式,現在可能不僅僅是基於LEMP的(E'代表'引擎x')但是,越來越多的做法是將Web伺服器推向基礎設施的邊緣,並以不同的方式圍繞它整合相同或經過改進的一組應用程式和資料庫工具。

nginx非常適合這一點,因為它提供了方便解除安裝併發,延遲處理,SSL(安全套接字層),靜態內容,壓縮和快取,連線和請求限制,甚至來自應用程式的HTTP媒體流所需的關鍵功能層到更有效的邊緣Web伺服器層。它還允許直接與memcached / Redis或其他“NoSQL”解決方案整合,以在為大量併發使用者提供服務時提高效能。

隨著最近開發套件和程式語言的廣泛使用,越來越多的公司正在改變他們的應用程式開發和部署習慣。 nginx已成為這些不斷變化的範例中最重要的組成部分之一,它已經幫助許多公司在預算範圍內快速啟動和開發其Web服務。

nginx的第一行是在2002年編寫的。2004年,它根據雙條款BSD許可證向公眾釋出。從那以後,nginx使用者的數量一直在增長,提供想法,並提交對整個社群非常有幫助和有益的錯誤報告,建議和觀察。

nginx程式碼庫是原創的,完全是用C程式語言從頭開始編寫的。 nginx已被移植到許多架構和作業系統,包括Linux,FreeBSD,Solaris,Mac OS X,AIX和Microsoft Windows。 nginx有自己的庫,除了zlib,PCRE和OpenSSL之外,它的標準模組除了系統的C庫之外沒有太多用處,如果不需要或者由於潛在的許可證衝突,可以選擇從構建中排除它們。

關於Windows版nginx的幾句話。雖然nginx適用於Windows環境,但nginx的Windows版本更像是概念驗證而不是功能齊全的埠。 nginx和Windows核心架構存在某些限制,目前這些架構不能很好地互動。 Windows的nginx版本的已知問題包括併發連線數量少得多,效能下降,沒有快取以及沒有頻寬監管。面向Windows的nginx的未來版本將更接近主流功能。

14.2 nginx架構概述

處理併發連線的傳統基於程序或執行緒的模型涉及使用單獨的程序或執行緒處理每個連線,以及阻止網路或輸入/輸出操作。根據應用程式的不同,記憶體和CPU消耗可能非常低效。生成單獨的程序或執行緒需要準備新的執行時環境,包括分配堆和堆疊記憶體,以及建立新的執行上下文。建立這些專案還需要額外的CPU時間,這可能最終導致由於過多的上下文切換時執行緒抖動導致的效能不佳。所有這些複雜性都表現在像Apache這樣的老式Web伺服器架構中。這是在提供豐富的一般適用功能和優化伺服器資源使用之間的權衡。

從一開始,nginx就是一種專業工具,可以實現更高的效能,密度和經濟地使用伺服器資源,同時實現網站的動態增長,因此它遵循不同的模式。實際上,它受到各種作業系統中基於事件的高階機制的持續開發的啟發。結果是模組化,事件驅動,非同步,單執行緒,非阻塞架構,它成為nginx程式碼的基礎。

nginx大量使用多路複用和事件通知,並將特定任務專用於單獨的程序。連線在一個名為workers的有限數量的單執行緒程序中以高效的執行迴圈進行處理。在每個worker中,nginx每秒可以處理數千個併發連線和請求。

程式碼結構

nginx工作器程式碼包括核心和功能模組。 nginx的核心負責維護一個嚴格的執行迴圈,並在每個請求處理階段執行模組程式碼的適當部分。模組構成了大部分表示和應用程式層功能。模組讀取和寫入網路和儲存,轉換內容,執行出站過濾,應用伺服器端包含操作,並在啟用代理時將請求傳遞給上游伺服器。

nginx的模組化架構通常允許開發人員擴充套件Web伺服器功能集,而無需修改nginx核心。 nginx模組的版本略有不同,即核心模組,事件模組,階段處理程式,協議,變數處理程式,過濾器,上游和負載平衡器。目前,nginx不支援動態載入的模組;即,模組在構建階段與核心一起編譯。但是,計劃在未來的主要版本中支援可載入模組和ABI。有關不同模組角色的更多詳細資訊,請參見第14.4節。

在處理與接受,處理和管理網路連線和內容檢索相關的各種操作時,nginx在Linux,Solaris和基於BSD的作業系統中使用事件通知機制和許多磁碟I / O效能增強,如kqueue,epoll,和事件埠。目標是儘可能多地提供作業系統的提示,以獲得入站和出站流量的及時非同步反饋,磁碟操作,讀取或寫入套接字,超時等。多路複用和高階I / O操作的不同方法的使用針對執行nginx的每個基於Unix的作業系統進行了大量優化。

圖14.1給出了nginx架構的高階概述。

                                                                圖14.1:nginx架構圖

Worker模型

如前所述,nginx不會為每個連線生成程序或執行緒。相反,工作程序接受來自共享“偵聽”套接字的新請求,並在每個工作程式內執行高效的執行迴圈,以處理每個工作程式數千個連線。在nginx中沒有專門的仲裁或與工人的連線分配;這項工作是由OS核心機制完成的。啟動時,會建立一組初始偵聽套接字。然後,工作人員在處理HTTP請求和響應時不斷接受,讀取和寫入套接字。

執行迴圈是nginx工作器程式碼中最複雜的部分。它包括全面的內部呼叫,並且在很大程度上依賴於非同步任務處理的想法。非同步操作通過模組化,事件通知,回撥函式的廣泛使用和微調定時器來實現。總的來說,關鍵原則是儘可能不阻塞。 nginx仍然可以阻止的唯一情況是當工作程序沒有足夠的磁碟儲存效能時。

因為nginx不會為每個連線分叉程序或執行緒,所以在絕大多數情況下,記憶體使用非常保守並且非常有效。 nginx也節省了CPU週期,因為程序或執行緒沒有正在進行的建立 - 銷燬模式。 nginx做的是檢查網路和儲存的狀態,初始化新連線,將它們新增到執行迴圈,並非同步處理直到完成,此時連線被解除分配並從執行迴圈中刪除。結合仔細使用系統呼叫和精確實現支援介面(如池和板記憶體分配器),即使在極端工作負載下,nginx通常也可實現中到低的CPU使用率。

因為nginx會產生幾個工作來處理連線,所以它可以跨多個核心很好地擴充套件。通常,每個核心的單獨工作程式允許充分利用多核架構,並防止執行緒抖動和鎖定。沒有資源匱乏,資源控制機制在單執行緒工作程序中是孤立的。此模型還允許跨物理儲存裝置實現更高的可伸縮性,有助於提高磁碟利用率並避免阻塞磁碟I / O.因此,在多個工作人員共享的工作負載下,可以更有效地利用伺服器資源。

對於某些磁碟使用和CPU負載模式,應調整nginx工作器的數量。這裡的規則有點基礎,系統管理員應該為他們的工作負載嘗試幾種配置。一般建議可能如下:如果負載模式是CPU密集型 - 例如,處理大量TCP / IP,執行SSL或壓縮 - nginx工作器的數量應與CPU核心數相匹配;如果負載主要是磁碟I / O繫結 - 例如,從儲存服務不同的內容集,或者重度代理 - 工作者數量可能是核心數量的1.5倍到2倍。一些工程師根據單個儲存單元的數量來選擇工人數量,但這種方法的效率取決於磁碟儲存的型別和配置。

nginx的開發人員將在即將推出的版本中解決的一個主要問題是如何避免磁碟I / O上的大部分阻塞。目前,如果沒有足夠的儲存效能來為特定工作人員生成的磁碟操作提供服務,那麼該工作人員仍可能阻止從磁碟讀取/寫入。存在許多機制和配置檔案指令以減輕此類磁碟I / O阻塞方案。最值得注意的是,sendfile和AIO等選項的組合通常會為磁碟效能帶來很大的空間。應根據資料集,nginx可用的記憶體量以及底層儲存架構來規劃nginx安裝。

現有工作模型的另一個問題與嵌入式指令碼的有限支援有關。首先,使用標準的nginx發行版,只支援嵌入Perl指令碼。有一個簡單的解釋:關鍵問題是嵌入式指令碼可能阻止任何操作或意外退出。這兩種行為都會立即導致工作人員被掛起,同時影響數千個連線。計劃進行更多工作,使nginx的嵌入式指令碼更簡單,更可靠,適用於更廣泛的應用程式。

nginx流程角色

nginx在記憶體中執行多個程序;有一個主程序和幾個工作程序。還有一些特殊用途的程序,特別是快取載入器和快取管理器。所有程序都是nginx版本1.x中的單執行緒。所有程序主要使用共享記憶體機制進行程序間通訊。主程序以root使用者身份執行。快取載入器,快取管理器和工作程式作為非特權使用者執行。

主程序負責以下任務:

  • 閱讀和驗證配置
  • 建立,繫結和關閉套接字
  • 啟動,終止和維護配置的工作程序數
  • 重新配置,無需中斷服務
  • 控制不間斷二進位制升級(啟動新二進位制並在必要時回滾)
  • 重新開啟日誌檔案
  • 編譯嵌入式Perl指令碼

工作程序接受,處理和處理來自客戶端的連線,提供反向代理和過濾功能,並執行nginx能夠執行的幾乎所有其他操作。關於監視nginx例項的行為,系統管理員應該關注工作人員,因為他們是反映Web伺服器的實際日常操作的過程。

快取載入器程序負責檢查磁碟快取項並使用快取元資料填充nginx的記憶體資料庫。本質上,快取載入器準備nginx例項以處理已經儲存在磁碟上的檔案,這些檔案位於特殊分配的目錄結構中。它遍歷目錄,檢查快取內容元資料,更新共享記憶體中的相關條目,然後在一切都乾淨並準備好使用時退出。

快取管理器主要負責快取過期和失效。它在正常的nginx操作期間保留在記憶體中,並在發生故障時由主程序重新啟動。

nginx快取概述

nginx中的快取是以檔案系統上的分層資料儲存的形式實現的。快取鍵是可配置的,並且可以使用不同的請求特定引數來控制進入快取的內容。快取金鑰和快取元資料儲存在共享記憶體段中,快取載入器,快取管理器和工作人員可以訪問這些記憶體段。目前,除了作業系統的虛擬檔案系統機制所暗示的優化之外,沒有任何記憶體中的檔案快取。每個快取的響應都放在檔案系統上的不同檔案中。層次結構(級別和命名細節)通過nginx配置指令控制。將響應寫入快取目錄結構時,檔案的路徑和名稱將從代理URL的MD5雜湊派生。

將內容放入快取的過程如下:當nginx從上游伺服器讀取響應時,首先將內容寫入快取目錄結構之外的臨時檔案。當nginx完成處理請求時,它會重新命名臨時檔案並將其移動到快取目錄。如果代理的臨時檔案目錄位於另一個檔案系統上,則會複製該檔案,因此建議將臨時目錄和快取目錄保留在同一檔案系統上。當需要明確清除檔案時,從快取目錄結構中刪除檔案也是非常安全的。 nginx有第三方擴充套件,可以遠端控制快取內容,並計劃在主要發行版中整合更多功能。

原文連結