論Web服務(wù)器的運(yùn)行速度,誰與Nginx爭鋒!
譯文在上一篇《Nginx風(fēng)頭正勁,Apache和IIS Web服務(wù)器遇到對手》文章中,我們介紹了在Web服務(wù)器系統(tǒng)管理員有了更多的選擇;主要的替代服務(wù)器之一:開源Nginx Web服務(wù)器正在迅速發(fā)展起來。本文介紹了如何在筆記本電腦上,通過Nginx處理每秒10000個請求的繁重任務(wù)。
說得好聽點(diǎn),我是個不大專業(yè)的系統(tǒng)管理員。我年輕時從事技術(shù)支持,后來在一個運(yùn)行幾個UNIX系統(tǒng)的Windows部門擔(dān)任管理員工作,這些系統(tǒng)大多放置在裝有空調(diào)的清潔機(jī)房里,由上了年紀(jì)的員工負(fù)責(zé)維護(hù)。直到我開始管理企業(yè)級存儲設(shè)備,才慢慢領(lǐng)教了bash外殼程序的強(qiáng)大功能,我那個拼湊起來的家庭網(wǎng)絡(luò)慢慢由支持幾臺個人電腦的Windows 2003域變成了GNU/Linux服務(wù)器和OS X臺式機(jī)及筆記本電腦組成的混合環(huán)境。
與大多數(shù)人一樣,我***也決定把自己的網(wǎng)站放到互聯(lián)網(wǎng)上,于是我使用Apache HTTP服務(wù)器來托管該網(wǎng)站。原因何在?因為我眼前就有一套Ubuntu服務(wù)器設(shè)備,而Apache服務(wù)器是我聽到次數(shù)最多的Web服務(wù)器。既然Apache對大型網(wǎng)站來說都足夠好,它對我這個小小的靜態(tài)個人網(wǎng)站來說理應(yīng)足夠好,不是嗎?
但沒想到,Apache對我來說不太好用。下面介紹了具體原因——我用了一個周末的時間扔掉原先安裝的Apache服務(wù)器,換成了Nginx的Web服務(wù)器:其守護(hù)程序占用資源少,運(yùn)行速度快。
#p# 老朽系統(tǒng)
Apache安裝起來很容易。我差點(diǎn)兒要寫成“太”容易了;但是如果你光有一身膽量,只曉得“Apache是托管運(yùn)行網(wǎng)站的某種軟件”,就想動手安裝Apache,那么恐怕面臨需要摸索學(xué)習(xí)的一個過程。不過,我在網(wǎng)上只搜索了一兩個小時以尋求幫助,鉆研Apache的配置文件,就建好了網(wǎng)站,它還是放在互聯(lián)網(wǎng)上的!幾個月后,Ars刊登了一篇文章,介紹如何獲得免費(fèi)的SSL/TLS證書(http://arstechnica.com/security/news/2009/12/how-to-get-set-with-a-secure-sertificate-for-free.ar)。我立馬想試一下——倒不是由于我真的很需要該證書,而是就想看看證書是如何工作的。此文刊登后沒過一天,我就為自己的域獲得了一份2級通配符SSL/TLS證書,我的Web服務(wù)器就有了https。
系統(tǒng)就這樣順利運(yùn)行了好幾年;但是當(dāng)我開始進(jìn)一步折騰Web服務(wù)器時,這一點(diǎn)開始顯露無遺:我安裝的系統(tǒng)盡管運(yùn)行順暢,但可以做得更好。尤其是,為Web服務(wù)器添加了Tectonicus后,我發(fā)現(xiàn)系統(tǒng)并非處于***運(yùn)行狀態(tài)。Tectonicus是一款沙盤游戲《Minecraft》地圖渲染工具,可以生成數(shù)以百萬講的小圖片,并且使用類似谷歌地圖(Google Maps)的界面,將眾多小圖片拼接起來。即使在我的本地網(wǎng)絡(luò)上,Apache也很難以相當(dāng)快的速度來顯示地圖。該Web服務(wù)器的硬件配置是雙核AMD E-350、2GB內(nèi)存和Vertex 2固態(tài)硬盤,理應(yīng)會立即顯示網(wǎng)站的靜態(tài)圖像。但是htop工具顯示,只要一顯示Tectonicus地圖,Apache進(jìn)程就瘋狂地占用處理器資源;屏幕慢慢填滿小圖片時,兩個處理器核心的使用率都達(dá)到了100%。
此外,我開始在同一套服務(wù)器設(shè)備上運(yùn)行一個小型維基。這使用Dokuwiki(http://www.dokuwiki.org/dokuwiki),該維基服務(wù)器可以使用皮膚,非常像MediaWiki,但是將數(shù)據(jù)存儲在平面文件中,并不需要數(shù)據(jù)庫。Dokuwiki需要PHP,這種廣泛使用的腳本語言用在全球數(shù)量眾多的Web服務(wù)器上,所以這意味著我需要將某種PHP軟件包安裝到我目前的環(huán)境中。
可以選擇的道路有好多條。由于我輕而易舉地將Apache安裝到Ubuntu上——只需輸入“sudo aptitude install apache2”,就得到了所謂的Apache MPM Prefork版本。這是最常安裝的Apache版本,其工作方式如下:創(chuàng)建許多獨(dú)立的Apache進(jìn)程,以處理Web請求。它不是使用多個線程,而是把任務(wù)劃分給多個子Apahce進(jìn)程。想好好了解進(jìn)程與線程的區(qū)別,請參閱關(guān)于該話題的這篇Ask Ars特寫文章(http://arstechnica.com/business/news/2011/04/ask-ars-what-is-a-cpu-thread.ars)。prefork是默認(rèn)的Apache安裝,因為Apache是一款可以擴(kuò)展的Web服務(wù)器,它可以進(jìn)行定制,只要添加模塊,就能執(zhí)行各種實用的操作;而人們可能想要安裝的一些模塊以多進(jìn)程方式運(yùn)行時無法順暢運(yùn)行。
用進(jìn)程來處理每項任務(wù)的缺點(diǎn)是,Apache的prefork模式比較占用內(nèi)存,在負(fù)載狀態(tài)下更是如此。Apache的另一種預(yù)編譯版本Apache MPM worker可以作為替代方案來安裝。worker有別于prefork的地方在于,worker的進(jìn)程是多線程的,因而它們能夠以較少的系統(tǒng)資源來滿足更多請求的需要。這就相當(dāng)于以較少的內(nèi)存和處理器資源更快地提供網(wǎng)頁。不過,由于一些Apache模塊在多線程Apache環(huán)境下運(yùn)行時未必能順暢地運(yùn)行,你得特意選擇該版本,使用軟件包管理器安裝到Ubuntu以及其他GNU/Linux發(fā)行版上。
稍微搜索一下,就發(fā)現(xiàn)Apache worker對于使得Tectonicus更快地顯示無數(shù)小圖片大有幫助,但是更換后會引起PHP方面出現(xiàn)一些問題。內(nèi)置的Apache PHP模塊“mod_php”屬于以多線程方式運(yùn)行可能有問題的那些模式。我面臨這個難題:丟棄并更換不少軟件,才能從mod_php改為獨(dú)立的PHP。
不過,Ars論壇成員Blacken00100的一個帖子(http://arstechnica.com/civis/viewtopic.php?p=22241073#p22241073)完全給了我新的方向。Apache結(jié)合獨(dú)立式PHP也許遠(yuǎn)不如像Nginx這些占用資源少的事件驅(qū)動型Web服務(wù)器結(jié)合獨(dú)立式PHP來得好。我的想法開始轉(zhuǎn)變。我想,只要我做好一些基本工作,也許可以一路過來,看看能不能安裝被廣泛認(rèn)為是當(dāng)今世界上運(yùn)行速度最快的Web服務(wù)器:Nginx。
后起之秀
Nginx是一款占用資源少的Web服務(wù)器,以超快的運(yùn)行速度超快而出名。它與Apache根本不一樣:Apache是進(jìn)程和線程驅(qū)動型的應(yīng)用軟件,而Nginx是事件驅(qū)動型的應(yīng)用軟件。這種設(shè)計上的差異所帶來的實際影響是,少量的Nginx“worker”進(jìn)程就能處理一大堆的請求,進(jìn)程之間不用等待對方,也不用同步;它們只要“閉上眼睛”,就能盡快地一口一口地吃掉大象(喻指繁重任務(wù))。
相比之下,Apache處理大量請求的方式是,生成更多的進(jìn)程來處理請求,這種做法通常耗用大量的內(nèi)存。Apache看到大象后,邊吃邊想大象有多大,有時Apache望著面前的沉重任務(wù)會有點(diǎn)發(fā)愁。另一方面,Nginx完全開始吞吃。
Chris Lea在為什么使用Nginx?網(wǎng)頁(http://wiki.nginx.org/WhyUseIt)上簡明扼要地概括了兩者的區(qū)別:“Apache好比是微軟Word,它有100萬個選項,但是你只需要其中6個。Nginx就處理那6項任務(wù),但處理其中5項任務(wù)時速度比Apache快50倍。”
Nginx在提供靜態(tài)文件時——比如Tectonicus地圖圖片圖像,表現(xiàn)尤為出色。對比較大的網(wǎng)站來說,它常常被用作前端Web服務(wù)器,以便迅速地提供沒有變化的網(wǎng)頁內(nèi)容,同時將針對動態(tài)內(nèi)容的請求轉(zhuǎn)交給其他地方運(yùn)行的更復(fù)雜的Apache Web服務(wù)器。不過,我感興趣的是它純粹作為一臺快速運(yùn)行的Web服務(wù)器。
與本文中提到的其他Web服務(wù)器一樣,只要用簡單的“sudo aptitude install Nginx”,很快就能從Ubuntu軟件包存儲庫獲得Nginx。我停掉Apache后,很快安裝好了Nginx。遵照Blacken的建議,我還改而安裝了php5-fpm,這是一款經(jīng)過大量改動的PHP軟件包,內(nèi)置了FastCGI功能。Blacken之所以建議選用php5-fpm,而不是比較舊、比較有名的php5-cgi套件,是因為fpm能夠根據(jù)服務(wù)器負(fù)載的需要來開啟或關(guān)閉新的PHP進(jìn)程,因而這是智能化程度高得多、功能強(qiáng)得大的軟件包;它所消耗的資源比較少,同時在負(fù)載狀態(tài)下可以透明地擴(kuò)展、保持速度。
如果你的要求很簡單,就像我這樣,那么用php5-fpm安裝可實際運(yùn)行的PHP很容易。主配置文件(/etc/php5/fpm/php-fpm.conf under Ubuntu 11.10)根本不需要改動,池配置文件(/etc/php5/fpm/pool.d/www.conf)只需要稍微調(diào)整一下。池配置文件定義了php5-fpm將如何接受來自Web服務(wù)器的CGI請求。默認(rèn)情況下,php5-fpm監(jiān)聽TCP端口9000,檢查來自Web服務(wù)器的請求,但我對此作了更改,改而使用Unix套接字文件,因為讓CGI請求通過本地TCP端口進(jìn)來稍稍帶來了一點(diǎn)延遲。除非你的網(wǎng)站在生成大量網(wǎng)頁,否則這可能不會有什么影響;但是我想用采取“正確”的做法。另外,池配置文件讓你可以指定池進(jìn)程以哪個用戶和用戶組來運(yùn)行——將這設(shè)成與Web服務(wù)器所使用的用戶和用戶組一模一樣是個好主意。
最重要的是,池配置文件讓你可以指定如果php-fpm配置成“動態(tài)”模式下,可以生成的PHP進(jìn)程的最小數(shù)量和***數(shù)量。這讓你開始時可以只用一兩個活動進(jìn)程來滿足PHP請求,但你可以指令php-fpm:根據(jù)需要,生成更多的進(jìn)程。唯一的實際限制是所能抽出來的內(nèi)存和處理器數(shù)量。至于我這個小型網(wǎng)站,我將php-fpm設(shè)成一開始只有一個進(jìn)程,最多可以生成10個進(jìn)程。***,池配置文件讓你可以指定傳統(tǒng)的PHP配置數(shù)值,比如***內(nèi)存使用量、***上傳文件大小、Sendmail二進(jìn)制文件的位置,等等。
#p# 配置Nginx
保存了配置文件、通過init腳本啟動該守護(hù)程序后,我有了一個完全實用的PHP環(huán)境;我準(zhǔn)備好了把注意力轉(zhuǎn)向這款Web服務(wù)器。如何針對Nginx改動現(xiàn)有的Apache配置——這種配置包括實用的SSL/TLS支持?
結(jié)果發(fā)現(xiàn),這其實相當(dāng)容易,因為Nginx配置起來根本不像Apache那么復(fù)雜。對于小型網(wǎng)站來說,這再好不過了!如果Nginx通過軟件包管理器安裝在Ubuntu下,就使用類似Apache的目錄結(jié)構(gòu)。凡是用戶可以配置的東西,都放在/etc/Nginx下;Nginx.conf文件用于存放所有的全局設(shè)置,conf.d目錄用于存放需要在運(yùn)行中配置里面解析和添加的額外配置文件,sites-available和sites-enabled目錄用于定義實際網(wǎng)站及其特定配置。
/etc/Nginx的內(nèi)容對Apache用戶來說有點(diǎn)似曾相識。
值得注意的是Nginx不能用來配置——它不支持.htaccess文件。你想在特定子目錄上完成的任何配置必須在配置文件或其中一個網(wǎng)站定義文件中進(jìn)行。如果你在考慮改用Nginx,你的網(wǎng)站又高度依賴.htaccess方面的技巧,用于定義訪問或用于添加重寫規(guī)則或其他任何規(guī)則,就需要重新評估一下,看看你所作的各種任務(wù)是否可以改而在配置文件中再現(xiàn)。這還意味著,專門依賴.htaccess文件的一些Web應(yīng)用程序在Nginx環(huán)境下可能無法順暢地運(yùn)行(或根本無法運(yùn)行)。
盡管如此,我的網(wǎng)站還是很適應(yīng)Nginx,主配置文件幾乎不需要什么編輯。主配置文件中最重要的設(shè)置就是“worker_processes”設(shè)置,它定義了有多少個Nginx進(jìn)程運(yùn)行。由于一個worker進(jìn)程就能同時處理數(shù)千個請求,一個可靠的經(jīng)驗法則就是,每個處理器核心使用一個worker進(jìn)程。以我為例,我將該設(shè)置設(shè)成了2。主配置文件還讓你可以指定Nginx進(jìn)程將作為哪個用戶來運(yùn)行;由于我通過軟件包管理器來安裝Nginx,這預(yù)先配置成www-data用戶,就跟Apache一樣。
配置的其余部分在sites-available目錄中進(jìn)行。就像Apache那樣,若使用Nginx,你在sites-available目錄中創(chuàng)建網(wǎng)站定義,然后為它們創(chuàng)建符號鏈接,指向sites-enabled目錄;Nginx在啟動時會解析網(wǎng)站定義。不過,不像在Apache中非SSL和SSL各有一個不同的文件,sites-available包含的“默認(rèn)”文件在里面同時定義了HTTP虛擬主機(jī)和HTTPS虛擬主機(jī)。
Nginx繼承了Apache的虛擬主機(jī)概念,提供了足夠多的配置選項,以滿足大多數(shù)網(wǎng)站的要求。你可以定義虛擬主機(jī)名稱、存放了所提供文件的Web根目錄,然后執(zhí)行任何特定的位置權(quán)限和指令。重寫也在同一個文件中處理,而不是像Apache那樣可能在多處執(zhí)行。這會導(dǎo)致網(wǎng)站定義文件比Apache網(wǎng)站的來得復(fù)雜,但是配置實現(xiàn)了集中化。
安裝SSL也有點(diǎn)不一樣,因為Nginx不像Apache那樣支持不同的鏈證書(chain certificate)。如果你網(wǎng)站的證書需要中級證書包(intermediate certificate bundle),就得把你網(wǎng)站的證書連入到證書包,然后才可以使用它。此外,提供帶SSL/TLS的文件時,Nginx默認(rèn)情況下在加密連接上使用極其安全但速度也極慢的DHE-RSA-AES256-SHA密碼。如果你需要為網(wǎng)頁提供非??煽康募用?,這很好;但是如果需要網(wǎng)頁迅速提供,就不太好,因為它另外添加的Diffie-Hellman加密是計算密集型操作。如果你要提供加密網(wǎng)頁,禁用DSE-RSA-AES256-SHA密碼、讓Nginx重新使用普通的AES256-SHA也許是個好主意。該網(wǎng)頁(http://matt.io/technobabble/hivemind_devops_alert:_nginx_does_not_suck_at_ssl/ur)上介紹了這么做的方法,以及關(guān)于該問題的另外一些信息。
為了讓Nginx正確地將PHP文件傳送到安裝的獨(dú)立式php-fpm,只要在需要使用PHP的每一個虛擬主機(jī)下安裝一個處理器(handler),就像這樣:
location ~ \.php$ { try_files $uri =404; fastcgi_pass unix:/var/run/php5-fpm.soc;}
這告訴Nginx:位于Web根目錄下任何地方的、以.php為后綴的任何文件都應(yīng)該通過/var/run/php5-fpm處的套接字與FastCGI一起傳送,這個地方表明了php5-fpm進(jìn)程在哪里監(jiān)聽出現(xiàn)的任務(wù)。
一個重要的提示是,Nginx與FastCGI和PHP結(jié)合使用時,存在一個眾所周知的潛在安全漏洞,這個漏洞會讓惡意訪客得以通過PHP處理器來發(fā)送非PHP文件。這個漏洞抓住了PHP的這個特點(diǎn):試圖盡量幫助處理Web服務(wù)器交由它處理的任務(wù)。可以告訴PHP執(zhí)行實際上并非以PHP為后綴的文件,只要為它提供以PHP為后綴的不正確文件名。可以設(shè)置php.ini中的一個選項,阻止這種情況發(fā)生,但是數(shù)量眾多的流行的PHP應(yīng)用程序?qū)嶋H上依賴這種幫忙過頭的行為,所以比較容易從服務(wù)器端來處理。這就是“try_files $uri =404;”這一行的用途——它指令Nginx先試圖提供它所獲得的準(zhǔn)確的統(tǒng)一資源標(biāo)識符(URI);如果該URI并不明確存在,就報告404錯誤,而不是將URI傳送到PHP。
網(wǎng)上的絕大多數(shù)Nginx + PHP教程沒有提到配置方面的這個陷阱,盡管它已存在了近兩年(我在這里提及,是因為它是個很容易避免的問題!)。
我對配置文件要做的其余工作涉及重寫,這一切與清除Dokuwiki URL、讓它們更容易閱讀有關(guān)。從Apache極其豐富的重寫語言轉(zhuǎn)為Nginx的重寫語言基本上不需要猜來測去;如果你的網(wǎng)站依賴大量重寫,你可能不想使用Nginx。它的重寫引擎其功能完全不如Apache的來得強(qiáng)大。
這套存放在.htaccess的重寫規(guī)則針對我那個托管運(yùn)行的維基,用來清理URL、處理安全登錄……
……Nginx中的大多數(shù)對應(yīng)的重寫規(guī)則
#p# 運(yùn)行順暢
好了,大功告成了。那么,Nginx運(yùn)行起來到底有多好?
它運(yùn)行起來確實很好。暫時不說PHP這部分,我想換成Nginx的主要原因是提供平面文件的速度。在我完全主觀性的測試中,Nginx在這方面完勝Apache。Tectonicus地圖以前需要數(shù)秒才能完全填滿屏幕,現(xiàn)在立即就能填滿;而且只要鼠標(biāo)有什么操作,它會立即響應(yīng)。拖動和縮放也很流暢、快速,不像同一個地圖在Apache環(huán)境下會出現(xiàn)滯后、漏過,好像它架設(shè)在南極州的靠倉鼠提供動力的服務(wù)器上,而不是架設(shè)在另一頭連至千兆以太網(wǎng)連接的局域網(wǎng)設(shè)備上。我滿意極了。
兩個Nginx worker進(jìn)程和單個的PHP-FPM池進(jìn)程,只用了大約14MB的物理內(nèi)存。
就基于PHP的維基而言,改善幅度有點(diǎn)不大明顯;但是無疑不比之前來得糟糕。維基上有幾個圖像密集型的網(wǎng)頁,通過Apache來裝入可能要花3至5秒;同樣的網(wǎng)頁裝入到Nginx上所需時間大致相當(dāng)。不過,Nginx+php-fpm環(huán)境占用的內(nèi)存資源比我之前所用的龐大Apache prefork配置環(huán)境少得多;在處理十幾個網(wǎng)頁裝入請求時,處理器的占用率也低得多。
這次更換只花了我周六的大半天時間,開始出現(xiàn)了幾個錯誤,后來在網(wǎng)上搜索了一番,時間主要花在了試圖搞定重寫規(guī)則、讓維基滿意上。我從這次經(jīng)驗中學(xué)到了很多東西,尤其是Nginx的表現(xiàn)確實名副其實——它是一臺運(yùn)行速度超快的Web服務(wù)器。
原文鏈接:http://arstechnica.com/business/news/2011/11/a-faster-web-server-ripping-out-apache-for-nginx.ars