摘要 簡(jiǎn)單可依賴的架構(gòu)首先需要有一個(gè)簡(jiǎn)單可依賴的前端WebServer集群。本文通過(guò)深入調(diào)研當(dāng)前主流的異步web服務(wù)器Lighttpd和Nginx,從業(yè)界使用情況、架構(gòu)原理、擴(kuò)展開(kāi)發(fā)、功能對(duì)比、性能對(duì)比等多個(gè)方面進(jìn)行分析。 調(diào)研分析業(yè)界相關(guān)從業(yè)界使用情況來(lái)看,最新Web Server使用情況的數(shù)據(jù)如下:Nginx的使用率是6.6%,Lighttpd的使用率是0.51%。 從文檔來(lái)看,nginx中文相關(guān)文檔越來(lái)越多。來(lái)自最新的百度搜索數(shù)據(jù)顯示,nginx的網(wǎng)頁(yè)數(shù)量是lighttpd的10倍。目前國(guó)內(nèi)對(duì)于Nignx內(nèi)核深入研究的人越來(lái)越多,有淘寶、sina、騰訊等許多大公司的技術(shù)人員參與研究,并進(jìn)行相關(guān)的技術(shù)交流。對(duì)于Lighttpd的研究,目前主要是公司內(nèi)部和一些學(xué)生。 從業(yè)界的點(diǎn)評(píng)來(lái)看,國(guó)內(nèi)外基本上結(jié)論如下:
從社區(qū)活躍度來(lái)看,Nginx每月2到3個(gè)三位版本發(fā)布。Lighttpd3位版本更新較慢,目前1.5的版本基本上沒(méi)有更新過(guò)。同時(shí)Nginx有豐富的第三方庫(kù)類。 架構(gòu)原理代碼層次 Nginx的代碼量10W行,Lighttpd是5W左右。相對(duì)來(lái)說(shuō),Nginx的代碼層次結(jié)構(gòu)更加分明,具體代碼結(jié)構(gòu)如下: Nginx和lighttpd都是采用C語(yǔ)言編寫的,對(duì)于基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)都有一定的處理。Nginx中關(guān)于數(shù)據(jù)結(jié)構(gòu)的代碼主要放在core文件夾里面。 Nginx主要的基礎(chǔ)代碼有:array、string、buf、file、hash、md5、內(nèi)存池、隊(duì)列、紅黑樹(shù)、time、共享鎖等。這些數(shù)據(jù)結(jié)構(gòu)對(duì)于擴(kuò)展開(kāi)發(fā)都非常有幫助。Lighttpd有一定的基礎(chǔ)數(shù)據(jù)封裝,但相對(duì)沒(méi)有那么明顯的設(shè)計(jì)。目前觀察到的基礎(chǔ)代碼有:bitset、buffer等。 內(nèi)存管理是所有C程序中非常值得關(guān)注的一點(diǎn)。Lighttpd在內(nèi)存管理上沒(méi)有做特殊的考慮,基本上都是采用系統(tǒng)內(nèi)存管理函數(shù),比如malloc/calloc等。在擴(kuò)展開(kāi)發(fā)中的內(nèi)存也需要擴(kuò)展模塊自己考慮。Nginx在內(nèi)存管理上提供了兩種方式:1、原生malloc等的二次封裝。2、內(nèi)存池。在nginx內(nèi)部大量的使用內(nèi)存池。在擴(kuò)展開(kāi)發(fā)中也能直接調(diào)用內(nèi)存池進(jìn)行內(nèi)存管理。此外,nginx還內(nèi)置了對(duì)tcmalloc的支持。把內(nèi)存優(yōu)化做到極致。 架構(gòu)層次 從總體架構(gòu)來(lái)看,Nginx/Lighttpd都屬于master+worker的工作模型。 但nginx相比lighttpd,在細(xì)節(jié)上處理的更加優(yōu)化,具體可以從幾個(gè)方面來(lái)談 1、 配置文件熱加載。Nginx從設(shè)計(jì)開(kāi)始就支持配置文件熱加載,甚至程序的熱加載。Lighttpd本身不支持,目前業(yè)界有采用擴(kuò)展方式,比如說(shuō)lua,可以實(shí)現(xiàn)部分配置熱加載。 2、 強(qiáng)大的master進(jìn)程,實(shí)現(xiàn)worker進(jìn)程和master進(jìn)程的各司其職。Lighttpd的master進(jìn)程在fork完worker進(jìn)程后,就單獨(dú)的等待worker進(jìn)程的結(jié)束(或者在worker進(jìn)程結(jié)束后再創(chuàng)建新的worker子進(jìn)程)。Nginx的master進(jìn)程負(fù)責(zé)對(duì)worker子進(jìn)程的管理,并通過(guò)socket pair通信方式實(shí)現(xiàn)熱配置文件升級(jí)、優(yōu)雅重啟、熱應(yīng)用程序升級(jí)等功能。 3、 線程鎖。Lighttpd在進(jìn)程之外還啟動(dòng)了線程進(jìn)行相關(guān)方面的工作,這會(huì)對(duì)lighttpd的性能帶來(lái)一定影響。Nginx內(nèi)部雖然提供了對(duì)線程模式的支持,但在主推的進(jìn)程模式中不會(huì)出現(xiàn)額外的線程。 4、 多核機(jī)器優(yōu)化,cpu affinity。Nginx設(shè)計(jì)中考慮了對(duì)多核機(jī)器的優(yōu)化方案,能降低進(jìn)程在不同cpu之間的切換次數(shù),從而提升性能。 超時(shí)處理 Lighttpd的超時(shí)處理原理非常簡(jiǎn)單:通過(guò)alarm信號(hào)量來(lái)實(shí)現(xiàn)的。每1s出發(fā)一個(gè)alarm信號(hào),從而切換到超時(shí)處理函數(shù)。該函數(shù)也非常簡(jiǎn)單:循環(huán)簡(jiǎn)單當(dāng)前所有連接的讀和寫,如果事件超時(shí)了,則直接close掉。這會(huì)有幾個(gè)問(wèn)題: 1、 連接非常多的時(shí)候。超時(shí)處理還是會(huì)非常耗事件的。隨著連接數(shù)而遞增。 2、 在不可重入的函數(shù)中出發(fā)alarm的時(shí)候,有可能出現(xiàn)意想不到的問(wèn)題。 3、 需要輪詢。 Nginx在超時(shí)處理上實(shí)現(xiàn)的巧妙的多:采用數(shù)據(jù)結(jié)構(gòu)和巧妙的策略來(lái)實(shí)現(xiàn)。 1、 使用紅黑樹(shù)來(lái)存放定時(shí)器的相關(guān)數(shù)據(jù)。紅黑樹(shù)的重要特點(diǎn)是:插入刪除都會(huì)在O(logN)完成,同時(shí)具有優(yōu)秀的查找性能。所以很多C++的庫(kù)(map)等都用到了它。 2、 通過(guò)紅黑樹(shù)計(jì)算出當(dāng)前節(jié)點(diǎn)的超時(shí)時(shí)間差,使用這個(gè)時(shí)間差作為調(diào)用多路復(fù)用I/O操作的參數(shù),當(dāng)函數(shù)返回,只可能是I/O事件被觸發(fā),或者超時(shí)。 3、 處理完I/O事件之后,得到處理前后的時(shí)間差,根據(jù)這個(gè)時(shí)間差依次查看紅黑樹(shù)中哪些定時(shí)器可以被處理。 這也是在高壓力下,Nginx更優(yōu)于Lighttpd的一個(gè)重要原因。 Accept 處理 Lighttpd中對(duì)于Accept的處理有幾個(gè)特點(diǎn):1、不加鎖。2、連接處理達(dá)到0.9的時(shí)候會(huì)禁止接收新的連接。3、1次性accpet 100個(gè)。這樣有一個(gè)好處, 假如服務(wù)器監(jiān)聽(tīng)fd是每次觸發(fā)只接收一個(gè)新的連接, 那么效率是比較低的,不如每次被觸發(fā)的時(shí)候”盡力”的去接收, 一直到接收了100個(gè)新的連接或者沒(méi)有可接收的連接之后才返回。4、提供了fdwaitqueue。在fd不夠用的時(shí)候備用。 Nginx:1、進(jìn)程加鎖,避免驚群,同時(shí)控制了獲取accpet的概率,一定程度上控制各個(gè)子進(jìn)程之間的請(qǐng)求數(shù)目。2、7/8閥值。連接數(shù)目達(dá)到最大連接數(shù)的7/8的時(shí)候,該進(jìn)程將獲取不到對(duì)應(yīng)的accept鎖。從而進(jìn)入安全控制階段。3、提供了multi_accept指令,在開(kāi)啟的情況下也和lighttpd一樣盡可能的多accept。 狀態(tài)機(jī) Lighttpd和nginx都是狀態(tài)機(jī)驅(qū)動(dòng)模型,兩者之間主要體現(xiàn)在細(xì)節(jié)的差異性上。
后端處理 Nginx針對(duì)不同的后端處理方式進(jìn)行了封裝,提供upstream來(lái)支持不同的協(xié)議(HTTP/FASTCGI/Memcache),提供擴(kuò)展來(lái)支持不同的負(fù)載均衡算法。同樣的Lighttpd在新版中也對(duì)不同的后端協(xié)議進(jìn)行了封裝,并提供了不同可供選擇的負(fù)載均衡算法。 從原理層次來(lái)看,兩者在后端處理上的思路是基本一致的。更多的對(duì)比需要從功能和性能上來(lái)對(duì)比。 擴(kuò)展開(kāi)發(fā) Nginx和Lighttpd都支持?jǐn)U展,Lighttpd是通過(guò)預(yù)留系統(tǒng)鉤子來(lái)實(shí)現(xiàn)的,相對(duì)來(lái)說(shuō)不夠靈活,如果有一些特殊的修改則不得不修改源碼。Nginx則通過(guò)預(yù)留系統(tǒng)鉤子和控制反轉(zhuǎn)結(jié)合,從而能夠?qū)崿F(xiàn)更多的功能。所以,nginx擴(kuò)展的靈活性高于Lighttpd。 總結(jié)如下: 1、 nginx不支持動(dòng)態(tài)擴(kuò)展模塊。 2、 擴(kuò)展開(kāi)發(fā)上,nginx更加靈活。提供了多種擴(kuò)展切入方式。 3、 Nginx提供了豐富的類庫(kù),方便擴(kuò)展開(kāi)發(fā)。 功能對(duì)比反向代理 對(duì)比分析如下: 1、 性能。
2、 功能。
結(jié)論: 1、功能上,nignx和lighttpd都具有完整的反向代理功能。但nginx在這方面明顯優(yōu)于lighttpd,更加完整的細(xì)節(jié)考慮和優(yōu)化。主要體現(xiàn)在超時(shí)處理、文件上傳、輸入輸出的過(guò)濾、cache等等。 2、性能上,Nginx稍優(yōu)于lighttpd。 Fastcgi 支持 Nginx和lighttpd在Fastcgi方面功能上基本上相同,主要調(diào)研是從性能上對(duì)比。 10k 的php 請(qǐng)求
20k 的PHP 請(qǐng)求
從性能數(shù)據(jù)來(lái)看,2000QPS以內(nèi),兩者性能差別不大,但高壓力下,兩者性能差別非常大。甚至有可能達(dá)到20%cpu差別。 頁(yè)面Cache 和運(yùn)維 Lighttpd目前暫無(wú)頁(yè)面Cache的支持。Nginx從設(shè)計(jì)之初就考慮了更改Cache。甚至有單獨(dú)的Cache管理進(jìn)程。 從功能上來(lái)看,目前Nginx已經(jīng)支持proxy cache和ssl filter,并且實(shí)現(xiàn)了對(duì)esi cache的支持。 從運(yùn)維上來(lái)看,Nginx支持配置熱加載,支持程序熱加載。更適合完成24*365的全天候不間斷服務(wù)。 總結(jié)對(duì)比點(diǎn)匯總整理后如下
通過(guò)上述對(duì)比分析,可以得出如下結(jié)論: “l(fā)ighttpd和nginx一樣具有非常好的架構(gòu),但在數(shù)據(jù)結(jié)構(gòu)、內(nèi)存管理都多個(gè)細(xì)節(jié)方面處理nginx考慮更加完善。如果說(shuō)lighttpd是異步web server的先驅(qū),那么nginx則是對(duì)lighttpd做了整體的優(yōu)化的。而這些優(yōu)化是全面的,根本性質(zhì)的。無(wú)法簡(jiǎn)單的通過(guò)升級(jí)lighttpd來(lái)實(shí)現(xiàn)。因?yàn)閚ginx從一開(kāi)始設(shè)計(jì)就希望做成一個(gè)完美的異步web server。nginx從event、跨平臺(tái)、基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)都很多細(xì)節(jié)方面進(jìn)行了考慮和優(yōu)化。應(yīng)該來(lái)說(shuō),nginx必定是未來(lái)的apache,未來(lái)的主流。” |
|