簡單可依賴的架構首先需要有一個簡單可依賴的前端WebServer叢集。本文通過深入調研目前主流的異步web伺服器Lighttpd和Nginx,從業界使用情況、架構原理、擴充開發、功能對比、性能對比等多個方面進行分析。
調研分析
業界相關
從業界使用情況來看,最新Web Server使用情況的資料如下:Nginx的使用率是6.6%,Lighttpd的使用率是0.51%。
從文檔來看,nginx中文相關文檔越來越多。來自最新的百度搜尋資料顯示,nginx的網頁數量是lighttpd的10倍。目前國内對于Nignx核心深入研究的人越來越多,有淘寶、sina、騰訊等許多大公司的技術人員參與研究,并進行相關的技術交流。對于Lighttpd的研究,目前主要是公司内部和一些學生。
從業界的點評來看,國内外基本上結論如下:
- 兩者都是異步WebServer,都采用了狀态機。本質上是相同的。
- Nginx穩定度高于Lighttpd。Lighttpd一直存在一定的記憶體洩漏。
- 性能上兩者都非常優秀,Nginx有一定優勢。
- Nginx在綜合性能上更加優秀,更有可能成為未來的apache。
從社群活躍度來看,Nginx每月2到3個三位版本釋出。Lighttpd3位版本更新較慢,目前1.5的版本基本上沒有更新過。同時Nginx有豐富的第三方庫類。
架構原理
代碼層次
Nginx的代碼量10W行,Lighttpd是5W左右。相對來說,Nginx的代碼層次結構更加分明,具體代碼結構如下:
Nginx和lighttpd都是采用C語言編寫的,對于基礎資料結構都有一定的處理。Nginx中關于資料結構的代碼主要放在core檔案夾裡面。
Nginx主要的基礎代碼有:array、string、buf、file、hash、md5、記憶體池、隊列、紅黑樹、time、共享鎖等。這些資料結構對于擴充開發都非常有幫助。Lighttpd有一定的基礎資料封裝,但相對沒有那麼明顯的設計。目前觀察到的基礎代碼有:bitset、buffer等。
記憶體管理是所有C程式中非常值得關注的一點。Lighttpd在記憶體管理上沒有做特殊的考慮,基本上都是采用系統記憶體管理函數,比如malloc/calloc等。在擴充開發中的記憶體也需要擴充子產品自己考慮。Nginx在記憶體管理上提供了兩種方式:1、原生malloc等的二次封裝。2、記憶體池。在nginx内部大量的使用記憶體池。在擴充開發中也能直接調用記憶體池進行記憶體管理。此外,nginx還内置了對tcmalloc的支援。把記憶體優化做到極緻。
架構層次
從總體架構來看,Nginx/Lighttpd都屬于master+worker的工作模型。
但nginx相比lighttpd,在細節上處理的更加優化,具體可以從幾個方面來談
1、 配置檔案熱加載。Nginx從設計開始就支援配置檔案熱加載,甚至程式的熱加載。Lighttpd本身不支援,目前業界有采用擴充方式,比如說lua,可以實作部配置設定置熱加載。
2、 強大的master程序,實作worker程序和master程序的各司其職。Lighttpd的master程序在fork完worker程序後,就單獨的等待worker程序的結束(或者在worker程序結束後再建立新的worker子程序)。Nginx的master程序負責對worker子程序的管理,并通過socket pair通信方式實作熱配置檔案更新、優雅重新開機、熱應用程式更新等功能。
3、 線程鎖。Lighttpd在程序之外還啟動了線程進行相關方面的工作,這會對lighttpd的性能帶來一定影響。Nginx内部雖然提供了對線程模式的支援,但在主推的程序模式中不會出現額外的線程。
4、 多核機器優化,cpu affinity。Nginx設計中考慮了對多核機器的優化方案,能降低程序在不同cpu之間的切換次數,進而提升性能。
逾時處理
Lighttpd的逾時處理原理非常簡單:通過alarm信号量來實作的。每1s出發一個alarm信号,進而切換到逾時處理函數。該函數也非常簡單:循環簡單目前所有連接配接的讀和寫,如果事件逾時了,則直接close掉。這會有幾個問題:
1、 連接配接非常多的時候。逾時處理還是會非常耗事件的。随着連接配接數而遞增。
2、 在不可重入的函數中出發alarm的時候,有可能出現意想不到的問題。
3、 需要輪詢。
Nginx在逾時處理上實作的巧妙的多:采用資料結構和巧妙的政策來實作。
1、 使用紅黑樹來存放定時器的相關資料。紅黑樹的重要特點是:插入删除都會在O(logN)完成,同時具有優秀的查找性能。是以很多C++的庫(map)等都用到了它。
2、 通過紅黑樹計算出目前節點的逾時時間差,使用這個時間差作為調用多路複用I/O操作的參數,當函數傳回,隻可能是I/O事件被觸發,或者逾時。
3、 處理完I/O事件之後,得到處理前後的時間差,根據這個時間差依次檢視紅黑樹中哪些定時器可以被處理。
這也是在高壓力下,Nginx更優于Lighttpd的一個重要原因。
Accept處理
Lighttpd中對于Accept的處理有幾個特點:1、不加鎖。2、連接配接處理達到0.9的時候會禁止接收新的連接配接。3、1次性accpet 100個。這樣有一個好處, 假如伺服器監聽fd是每次觸發隻接收一個新的連接配接, 那麼效率是比較低的,不如每次被觸發的時候”盡力”的去接收, 一直到接收了100個新的連接配接或者沒有可接收的連接配接之後才傳回。4、提供了fdwaitqueue。在fd不夠用的時候備用。
Nginx:1、程序加鎖,避免驚群,同時控制了擷取accpet的機率,一定程度上控制各個子程序之間的請求數目。2、7/8閥值。連接配接數目達到最大連接配接數的7/8的時候,該程序将擷取不到對應的accept鎖。進而進入安全控制階段。3、提供了multi_accept指令,在開啟的情況下也和lighttpd一樣盡可能的多accept。
狀态機
Lighttpd和nginx都是狀态機驅動模型,兩者之間主要展現在細節的差異性上。
- Nginx對整個狀态進行了分類,分成預處理、狀态機、filter流程三個明顯的階段。
- Lighttpd的狀态機相對簡單固定。Nginx則相對靈活。
- Nginx的大部分處理狀态都是可以擴充的并且可中斷的。Lighttpd在部分狀态中也可以擴充的。
- 耦合程度。nginx狀态處理函數之間的耦合緊密,狀态切換時的下一步處理由狀态處理函數來決。而lighttpd将狀态切換的動作放在狀态機裡,各個狀态處理函數不關心下一步需要做什麼,狀态之間的耦合小。但同時會對擴充性帶來一些問題,比如說subrequest的實作。
後端處理
Nginx針對不同的後端處理方式進行了封裝,提供upstream來支援不同的協定(HTTP/FASTCGI/Memcache),提供擴充來支援不同的負載均衡算法。同樣的Lighttpd在新版中也對不同的後端協定進行了封裝,并提供了不同可供選擇的負載均衡算法。
從原理層次來看,兩者在後端處理上的思路是基本一緻的。更多的對比需要從功能和性能上來對比。
擴充開發
Nginx和Lighttpd都支援擴充,Lighttpd是通過預留系統鈎子來實作的,相對來說不夠靈活,如果有一些特殊的修改則不得不修改源碼。Nginx則通過預留系統鈎子和控制反轉結合,進而能夠實作更多的功能。是以,nginx擴充的靈活性高于Lighttpd。
總結如下:
1、 nginx不支援動态擴充子產品。
2、 擴充開發上,nginx更加靈活。提供了多種擴充切入方式。
3、 Nginx提供了豐富的類庫,友善擴充開發。
功能對比
反向代理
對比分析如下:
1、 性能。
- 同等壓力下,nginx的cpu消耗要低于lighttpd。但整體差别不大。
- 極限壓力下,nginx處理能力高于lighttpd。原因未知。
2、 功能。
功能點 | Lighttpd | Nginx | 備注 |
靈活的反向代理方式 | 支援 | 支援 | 都非常好 |
正則 | 支援 | 支援 | |
自定義header頭 | 部分支援 | 支援 | 目前gm有庫支援IP的傳遞 |
負載均衡 | 支援 | 支援 | |
逾時處理 | 支援 | 支援連接配接、讀寫等 | |
故障處理 | 支援 | 支援 | |
Cache | 不支援 | 支援 | |
檔案上傳 | 未知 | 支援,可配置,有優化 | Transmit不支援 |
輸出過濾 | 不支援 | 支援 | 頭部過濾和内容過濾。 |
結論:
1、功能上,nignx和lighttpd都具有完整的反向代理功能。但nginx在這方面明顯優于lighttpd,更加完整的細節考慮和優化。主要展現在逾時處理、檔案上傳、輸入輸出的過濾、cache等等。
2、性能上,Nginx稍優于lighttpd。
Fastcgi支援
Nginx和lighttpd在Fastcgi方面功能上基本上相同,主要調研是從性能上對比。
10k的php請求
前端壓力 | Lighttpd | Nginx | 備注 |
1000QPS | 96% 處理1000QPS | 98% | |
2000QPS | 91% | 96% | |
4000QPS | 81% | 92% | |
8000QPS | 65% | 85% |
20k的PHP請求
前端壓力 | Lighttpd | Nginx | 備注 |
1000QPS | 95% 處理1000QPS | 98% | |
2000QPS | 90% | 95% | |
4000QPS | 80% | 90% | |
8000QPS | 63%實際處理5588 QPS | 86%。實際處理5220QPS |
從性能資料來看,2000QPS以内,兩者性能差别不大,但高壓力下,兩者性能差别非常大。甚至有可能達到20%cpu差别。
頁面Cache和運維
Lighttpd目前暫無頁面Cache的支援。Nginx從設計之初就考慮了更改Cache。甚至有單獨的Cache管理程序。
從功能上來看,目前Nginx已經支援proxy cache和ssl filter,并且實作了對esi cache的支援。
從運維上來看,Nginx支援配置熱加載,支援程式熱加載。更适合完成24*365的全天候不間斷服務。
總結
對比點彙總整理後如下
對比點 | Nginx | Lighttpd | 備注 |
市場占有率 | 6.6% | 0.5% | |
文檔 | 百度文檔10:1Google文檔 1:1 國内研究人員nginx>lighttpd | ||
業界點評 | 更加看好Nginx | ||
代碼量 | 10W | 5W | Nginx的代碼結構層次較好。 |
基礎資料結構 | array、string、buf、file、hash、md5、記憶體池、隊列、紅黑樹、time、共享鎖 | bitset、buffer | 豐富的庫類對擴充開發有很大幫助 |
記憶體管理 | 原生malloc、記憶體池、支援tcmalloc | 原生malloc | |
配置檔案熱加載 | 支援 | 不支援 | |
程序模型 | Master負責管理,worker負責處理請求,各司其職。 | Master簡單。Worker複雜 | |
程序額外線程 | 無 | 有 | 存線上程鎖 |
多核機器優化 | 支援 | 不支援 | |
連接配接管理 | 靜态數組+單連結清單 | 動态數組,key互動 | Nginx更加穩定高效。 |
逾時處理 | 紅黑樹+巧妙的政策 | Alarm+for循環 | |
Accept處理 | 鎖+7/8閥值,支援mult accept | 0.9政策,一次性aceept100個。 | |
狀态機 |
| ||
後端處理 | 都支援多種協定,并且友善擴充,都支援負載均衡算法擴充。 | ||
擴充開發 | 1、 預定義鈎子2、 控制反轉 3、 豐富庫類 | 預定義鈎子 | |
反向代理 | 1、功能上,nignx和lighttpd都具有完整的反向代理功能。但nginx在這方面明顯優于lighttpd,更加完整的細節考慮和優化。主要展現在逾時處理、檔案上傳、輸入輸出的過濾、cache等等。2、性能上,Nginx稍優于lighttpd。 | ||
fastcgi | 功能上兩者差别不大,主要展現在性能上。在性能上,2000QPS以内,兩者性能差别不大,但高壓力下,兩者性能差别非常大。 | ||
頁面Cache | 支援proxy_cache。支援esi頁面cache | 不支援,需要額外開發。 | |
運維相關 | 支援配置檔案熱加載支援應用程式熱加載 | 支援有限的配置檔案熱加載 |
通過上述對比分析,可以得出如下結論:
“lighttpd和nginx一樣具有非常好的架構,但在資料結構、記憶體管理都多個細節方面處理nginx考慮更加完善。如果說lighttpd是異步web server的先驅,那麼nginx則是對lighttpd做了整體的優化的。而這些優化是全面的,根本性質的。無法簡單的通過更新lighttpd來實作。因為nginx從一開始設計就希望做成一個完美的異步web server。nginx從event、跨平台、基礎資料結構都很多細節方面進行了考慮和優化。應該來說,nginx必定是未來的apache,未來的主流。”
by xuliqiang