卷2:第14章 NginX

2018-02-24 15:55 更新

原文:http://www.aosabook.org/en/nginx.html

作者:?Andrew Alexeev

nginx(發(fā)音"engine x")是俄羅斯軟件工程師Igor Sysoev開發(fā)的免費開源web服務器軟件。nginx于2004年發(fā)布,聚焦于高性能,高并發(fā)和低內(nèi)存消耗問題。并且具有多種web服務器功能特性:負載均衡,緩存,訪問控制,帶寬控制,以及高效整合各種應用的能力,這些特性使nginx很適合于現(xiàn)代網(wǎng)站架構。目前,nginx已經(jīng)是互聯(lián)網(wǎng)上第二流行的開源web服務器軟件。

14.1 為什么高并發(fā)重要

和十年前相比,目前的互聯(lián)網(wǎng)已經(jīng)難以想象的廣泛應用和普及。從NCSA用Apache搭的web服務器提供的可點擊的文本HTML,已然進化成超過20億人在線的通信媒介。隨著永久在線的個人電腦,移動終端以及平板電腦的增多,互聯(lián)網(wǎng)在快速變化,經(jīng)濟系統(tǒng)也完全數(shù)字有線化。提供實時可用信息和娛樂的在線服務變得更加復雜精巧。在線業(yè)務的安全需求也急劇變化。網(wǎng)站比從前更加復雜,需要在工程上做的更具有健壯性和可伸縮性。

并發(fā)總是網(wǎng)站架構最大的挑戰(zhàn)之一。由于web服務的興起,并發(fā)的數(shù)量級在不斷增長。熱門網(wǎng)站為幾十萬甚至幾百萬的同時在線用戶提供服務并不尋常。十年前,并發(fā)的主要原因是由于客戶端接入速度慢--用戶使用ADSL或者撥號商務?,F(xiàn)在,并發(fā)是由移動終端和新應用架構所帶來,這些應用通?;诔志眠B接來為客戶端提供新聞,微博,通知等服務。另一個重要的因素就是現(xiàn)代瀏覽器行為變了,他們?yōu)g覽網(wǎng)站的時候會同時打開4到6個連接來加快頁面加載速度。

舉例說明一下慢客戶端的問題,假設一個Apache網(wǎng)站產(chǎn)生小于100KB的響應--包含文本或圖片的網(wǎng)頁。生成這個頁面可能需要1秒鐘,但是如果網(wǎng)速只有80kbps(10KB/s),需要花10秒才能把這個頁面發(fā)送到客戶端?;旧希瑆eb服務器相對快速的推送100KB數(shù)據(jù),然后需要等待10秒發(fā)送數(shù)據(jù)之后才能關閉連接。那么現(xiàn)在如果有1000個同時連接的客戶端請求相同的頁面,那么如果為每個客戶端分配1MB內(nèi)存,就需要1000MB內(nèi)存來為這1000個客戶端提供這個頁面。實際上,一個典型的基于Apache的web服務器通常為每個連接分配1MB內(nèi)存,而移動通信的有效速度也通常是幾十kbps。雖然借助于增加操作系統(tǒng)內(nèi)核socket緩沖區(qū)大小,可以優(yōu)化發(fā)送數(shù)據(jù)給慢客戶端的場景,但是這并不是一個常規(guī)的解決方案,并且會帶來無法預料的副作用。

隨著持久連接的使用,并發(fā)處理的問題更加明顯。為了避免新建HTTP連接所帶來的延時,客戶端需要保持連接,這樣web服務器就需要為每個連接上的客戶端分配一定數(shù)量的內(nèi)存。

因此,為了處理持續(xù)增長的用戶帶來的負載和更高量級的并發(fā),網(wǎng)站需要大量高效的組件。而另一方面,web服務器軟件運行在諸如硬件(CPU,內(nèi)存,磁盤),網(wǎng)絡帶寬,應用和數(shù)據(jù)存儲架構等之上,這些基礎設施顯然也很重要。因而,隨著同時在線數(shù)和每秒請求數(shù)的增長,web服務器性能也應該能夠非線性擴展。

Apache不再適用?

Apache web服務器軟件發(fā)源于1990年代,目前在互聯(lián)網(wǎng)網(wǎng)站上占有率第一。Apache的架構適合當時的操作系統(tǒng)和硬件,并且也符合當時的互聯(lián)網(wǎng)狀況:一個網(wǎng)站通常使用一臺物理服務器運行一個Apache實例。2000年之后,顯然這種單服務器模型已經(jīng)無法簡單擴展來滿足日益增長的web服務需求。雖然Apache為新功能開發(fā)提供了堅實的基礎,但他為每個新連接派生一個進程的做法(譯注:Apache從2.4版本起已經(jīng)支持事件模型),不適合網(wǎng)站的非線性擴展。最終,Apache成為一個通用的web服務器軟件,聚焦于功能多樣化,第三方擴展開發(fā),以及web應用開發(fā)的通用性。然而,當硬件成本越來越低,每個連接消耗的CPU和內(nèi)存越來越多,使用這樣功能繁多的單一軟件不再具有可伸縮性。

因而,當服務器硬件、操作系統(tǒng)和網(wǎng)絡設施不再成為網(wǎng)站增長的主要限制因素時,網(wǎng)站開發(fā)者開始尋求更高效的手段來架設web服務器。大約十年前,著名軟件工程師Daniel Kegel提出:“是時候讓web服務器支持同時處理10000客戶端了”,并且預言了現(xiàn)在稱為云服務的技術。Kegel的C10K設想明顯推動了許多人嘗試解決這個問題--通過優(yōu)化web服務器軟件來支持大規(guī)模客戶端連接的并發(fā)處理,nginx是其中做的最成功者之一。

為了解決10000個并發(fā)連接的C10K問題,nginx基于一個完全不同的架構—更適合每秒同時連接數(shù)和請求數(shù)非線性增長。Nginx基于事件模型,而沒有模仿Apache為每個請求派生新進程或線程的做法。最終結果就是即使負載增加了,內(nèi)存和CPU使用事件始終保持可預期。Nginx使用普通的硬件就能在一個服務器上處理數(shù)萬的并發(fā)連接。

Nginx的第一個版本發(fā)布之后,一般被用來同Apache一同部署,HTML、CSS、JavaScript腳本和圖片等靜態(tài)內(nèi)容由nginx處理,來降低Apache應用服務器的并發(fā)和延時。隨著開發(fā)演進的過程,nginx增加了FastCGI、uswge和SCGI等協(xié)議的支持,以及對分布式內(nèi)存對象緩存系統(tǒng)如memcached的支持。也增加了其他有用的功能,例如支持負載均衡和緩存的反向代理。這些附加功能使nginx成為一個高效的工具集,用于構建可伸縮的web基礎設施。

2012年2月,Apache 2.4.x版本發(fā)布。雖然增加了新的并發(fā)處理核心模塊和代理模塊,用于加強可伸縮性和性能,但要說性能、并發(fā)能力和資源利用率是否能趕上或超過純事件驅(qū)動模型的web服務器還為時尚早。Apache新版本具有了更好的性能值得高興,對于nginx+Apache的web網(wǎng)站架構,雖然這能夠緩解后端潛在的瓶頸,但并不能解決全部問題。

nginx有更多的優(yōu)點嗎?

部署nginx最關鍵的好處就是能夠高性能高效的處理高并發(fā)。同時,還有更多有意思的好處。

最近幾年,web架構擁抱解耦的理念并且將應用層設施從web服務器中分離。雖然現(xiàn)在僅僅是將原先基于LAMP(Linux, Apache, MySQL, PHP, Python or Perl)所構建的網(wǎng)站,變?yōu)榛贚EMP(E表示Engine x)的。但是,越來越多的實踐是將web服務器推入基礎設施的邊緣,并且用不同的方法整合這些相同或更新的應用和數(shù)據(jù)庫工具集。

Nginx很適合做這些工作。他提供了必要的關鍵功能用于方便將下列功能從應用層剝離到更高效的邊緣web服務器層:并發(fā)、長連接處理、SSL,靜態(tài)內(nèi)容、壓縮和緩存、連接和請求限速,以及HTTP媒體流等。Nginx同時也允許直接整合memcached、Redis或者其他的NoSQL解決方案,增強為處理大規(guī)模并發(fā)用戶的性能。

隨著現(xiàn)代編程語言和開發(fā)包廣泛使用,越來越多的公司改變了應用開發(fā)和部署的方式。Nginx已經(jīng)成為這些改變范例之中的最重要的部件之一,并且已經(jīng)幫助許多公司在預算內(nèi)快速啟動和開發(fā)他們的web服務。

Nginx開發(fā)始于2002年,2004年基于2-clause BSD授權正式對外發(fā)布。自發(fā)布起,Nginx用戶就在不斷增長,并且貢獻提議,提交bug報告、建議和評測報告,這極大的幫助和促進了整個社區(qū)的發(fā)展。

Nginx代碼完全用C語言從頭寫成,已經(jīng)移植到許多體系結構和操作系統(tǒng),包括:Linux、FreeBSD、Solaris、Mac OS X、AIX以及Microsoft Windows。Nginx有自己的函數(shù)庫,并且除了zlib、PCRE和OpenSSL之外,標準模塊只使用系統(tǒng)C庫函數(shù)。而且,如果不需要或者考慮到潛在的授權沖突,可以不使用這些第三方庫。

談談關于Windows版本nginx。當nignx在Windows環(huán)境下工作時,Windows版本的nginx更像是概念驗證版本,而不是全功能移植。這是由于目前nginx和Windows內(nèi)核架構之間交互的某些限制導致。Windows版本ngnix已知的問題包括:低并發(fā)連接數(shù)、性能降低、不支持緩存和帶寬策略。未來Windows版本的nginx的功能會更接近主流版本。

14.2 Nginx架構綜覽

傳統(tǒng)基于進程或線程的模型使用單獨的進程或線程處理并發(fā)連接,因而會阻塞于網(wǎng)絡或I/O操作。根據(jù)不同的應用,就內(nèi)存和CPU而言,這是非常低效的。派生進程或線程需要準備新的運行環(huán)境,包括在內(nèi)存上分配堆和棧、生成一個新的運行上下文。創(chuàng)建這些東西還需要額外的CPU時間,而且過度的上下文切換引起的線程抖動最終會導致性能低下。所有這些復雜性在如Apache web服務器的老架構上一覽無遺。在提供豐富的通用應用功能和優(yōu)化服務器資源使用之間需要做一個權衡。

最早的時候,nginx希望為動態(tài)增長的網(wǎng)站獲得更好的性能,并且密集高效的使用服務器資源,所以其使用了另外一個模型。受不斷發(fā)展的在不同操作系統(tǒng)上開發(fā)基于事件模型的技術驅(qū)動,最終一個模塊化,事件驅(qū)動,異步,單線程,非阻塞架構成為nginx代碼的基礎。

Nginx大量使用多路復用和事件通知,并且給不同的進程分配不同的任務。數(shù)量有限的工作進程(Worker)使用高效的單線程循環(huán)處理連接。每個worker進程每秒可以處理數(shù)千個并發(fā)連接、請求。

代碼結構

Nginx worker的代碼包含核心和功能模塊。核心負責維護一個緊湊的事件處理循環(huán),并且在請求處理的每個階段執(zhí)行對應的模塊代碼段。模塊完成了大部分展現(xiàn)和應用層功能。包括從網(wǎng)絡和存儲設備讀取、寫入,轉換內(nèi)容,進行輸出過濾,SSI(server-side include)處理,或者如果啟用代理則轉發(fā)請求給后端服務器。

nginx模塊化的架構允許開發(fā)者擴展web服務器的功能,而不需要修改nginx核心。Nginx模塊可分為:核心、事件模塊,階段處理器,協(xié)議、變量處理器,過濾器,上游和負載均衡器等。目前,nginx不支持動態(tài)加載模塊,即模塊代碼是和nginx核心代碼一起編譯的。模塊動態(tài)加載和ABI已經(jīng)計劃在將來的某個版本開發(fā)。更多關于不同模塊角色的詳細信息可在14.4章找到。

Nginx在Linux、Solaris和BSD系統(tǒng)上使用kqueue、epoll和event ports等技術,通過事件通知機制來處理網(wǎng)絡連接和內(nèi)容獲取,包括接受、處理和管理連接,并且大大增強了磁盤IO性能。目的在于盡可能的提供操作系統(tǒng)建議的手段,用于從網(wǎng)絡進出流量,磁盤操作,套接字讀取和寫入,超時等事件中及時異步地獲取反饋。Nginx為每個基于Unix的操作系統(tǒng)大量優(yōu)化了這些多路復用和高級I/O操作的方法。

圖14.1展示了nginx架構的高層設計。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號