簡單可依賴的架構首先需要有一個簡單可依賴的前端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