最近我們的下載服務遭遇了c30k,導致nginx的下載服務近乎停滯。原因嘛,很簡單,服務器部署在國外,眾所周知的原因,SL機房的線路不穩,加上不同地區出口速率抖動很厲害,為了加速下載,我們放開了限制,允許用戶使用多線程的下載工具。這樣一來,自然產生了c10k問題。下載文件都不小,每個用戶至少使用4線程,同時下載若干個素材。。。很自然并發鏈接數30k以上。
更受限于手頭money,無法擴容(實際上要有錢也不會跑國外)。因此,必須提高單機并發能力和吞吐量。
我們的下載服務是使用Perl寫的一個Plack應用,典型的PSGI,實現下載驗證,實時防火墻,用戶下載跟蹤等等,無法直接使用靜態文件分發(實際上Perl的性能還是很高效的,部署于Starman,對比PHP的實現,是后者(PHP-FPM)的10倍左右)。
Starman是一個很不錯的PSGI Server,它使用傳統的Prefork模式。即便高效,但Prefork確實無法有效應對c10k,我無法把Starman的worker增大到幾百上千個。在以前的文章曾經提到Evented IO是能夠應付c10k的一個方案。因此,我使用Twiggy換下了Starman。Twiggy是基于AE(AnyEvent)的一個PSGI Server,單進程。在低并發下,單進程的Twiggy的qps是弱于Starman,不過到了高并發,Twiggy的優勢就顯現出來了。在實際部署中,我啟動了多個Twiggy進程,分別監聽獨立的端口,nginx則使用upstream進行負載均衡。 10個Twiggy的吞吐量已經遠遠超過了50個Starman worker。 Twiggy的開銷也不大,因此可以很放心的增加Twiggy的進程。
感謝PSGI的接口規范,從Starman切換到Twiggy,應用程序無需做任何改動。(前提是程序內不能有阻塞io的操作)。
另一個問題是服務器的IO-Wait比較高,畢竟下載這個是IO-Bound的任務。
Nginx支持Linux Native AIO,因此我考慮是否使用AIO能夠大大降低IO-Wait? 性能應該有比較明顯的提升?
網上有一些資料,吹噓的Nginx AIO性能提升,神奇云云。我有點將信將疑,因為都沒有任何的測試數據比較,均是人云亦云。另外,多數配置都是或多或少有問題的。
我使用的CentOS, Nginx AIO要使用,必須是CentOS 5.5以上。因為只有5.5的kernel才有AIO的backport,nginx并沒有使用libaio。
此外,Nginx的AIO本來是為FreeBSD開發,Linux固然可以使用,不過受到了Linux AIO的很多限制。
1. 必須使用Direct IO. 這樣一來,導致無法使用vm的disk cache.
2. 文件只有大小和directio_alignment定義block size整數倍的數據才可以使用AIO,當文件整數據塊之前和之后,那些不能取整的部分則是blocking方式讀取的,這也是為什么需要output-buffer。directio_alignment大小取決于你使用的文件系統,默認是512,而對于XFS,注意,如果你沒有修改XFS bsize, 需要調整為XFS默認的4k.
新聞熱點
疑難解答