當(dāng)前web2.0革命風(fēng)起云涌,web2.0強(qiáng)調(diào)服務(wù),而服務(wù)最基本的要求是速度快和穩(wěn)定,離開這兩個(gè)談功能強(qiáng)大和易用性都沒有任何意義。本文介紹一些關(guān)于筆者運(yùn)營(yíng)一個(gè)web2.0網(wǎng)站的優(yōu)化心得和經(jīng)驗(yàn),希望能夠和大家共同探討。
Web2.0網(wǎng)站不同于以往以靜態(tài)信息為主的網(wǎng)站架構(gòu),以往的結(jié)構(gòu)大體分為2層,一個(gè)是客戶端瀏覽器,一個(gè)就是web服務(wù)器;而web2.0以動(dòng)態(tài)和交互為主,一般是3層或者4層,在靜態(tài)信息網(wǎng)站的結(jié)構(gòu)上的web服務(wù)器后端會(huì)增加應(yīng)用服務(wù)器和數(shù)據(jù)庫(kù)。一般會(huì)把瀏覽器和web服務(wù)器歸為最上一層即為web層,應(yīng)用服務(wù)器為中間一層,數(shù)據(jù)庫(kù)為最底層。從優(yōu)化角度來講,越上層優(yōu)化獲得益處越大,優(yōu)化也是從上自下而來。
Web層優(yōu)化
DNS的解析時(shí)間
這個(gè)時(shí)間就是在用戶第一次訪問網(wǎng)站的時(shí)候產(chǎn)生,解析時(shí)間會(huì)影響用戶的訪問感受,因此想要網(wǎng)站響應(yīng)速度快,第一就是不要在DNS解析上產(chǎn)生問題。另外DNS的TTL時(shí)間也要考量,IE的DNS過期時(shí)間是30分鐘,TTL設(shè)置的比這個(gè)長(zhǎng)一點(diǎn)就可以。另外在web服務(wù)器上使用keep-live也會(huì)減少DNS查詢次數(shù)。
降低瀏覽器發(fā)起請(qǐng)求的數(shù)量
盡量降低瀏覽器發(fā)起請(qǐng)求的數(shù)量,就是說盡量能夠讓瀏覽器緩存任何可以緩存的東西。這樣當(dāng)用戶訪問過一次后,第二次訪問可能會(huì)使得發(fā)起的請(qǐng)求數(shù)趨近1或者等于1,如果是靜態(tài)的頁(yè)面則可能是0。方法包括:
把所有的樣式表文件并為1個(gè)
把所有的js文件并成1個(gè)
圖片盡量能夠合成1張,這個(gè)跟以前不一樣,現(xiàn)在大多數(shù)是adsl上網(wǎng),反而是大量的零碎圖片能夠影響速度
頁(yè)面布局與樣式
頁(yè)面采用xhtml,采用div+css布局,而把樣式表和xhtml文件分開,一則能夠降低xhtml文件大小,二則能夠?qū)邮奖砦募M(jìn)行其他緩存處理。這里還有個(gè)ui設(shè)計(jì)的原則,ui跟系統(tǒng)結(jié)構(gòu)一樣,越簡(jiǎn)潔越好,這樣整體頁(yè)面代碼會(huì)比較少,速度也會(huì)比較不錯(cuò)。
JavaScript文件
JavaScript文件也最好放到html文件外,原因同上。
靜態(tài)文件的優(yōu)化方法
a)目前大多數(shù)的瀏覽器都支持gzip壓縮文件,因此為文本、靜態(tài)頁(yè)面、樣式表、JavaScript文件等可以壓縮處理的文件進(jìn)行壓縮處理能夠減少內(nèi)容獲取時(shí)間,一般壓縮完的大小為原大小的10-30%。這個(gè)在apache等web服務(wù)器上進(jìn)行設(shè)置,筆者使用lighttpd的設(shè)置為:
server.modules = (
….
"mod_compress",
…
)
compress.cache-dir="/usr/local/lighttpd/cache"
compress.filetype = ("text/plain", "text/html", "text/css", "text/javascript")
b)還可以在靜態(tài)文件服務(wù)器前面增加緩存服務(wù)器比如squid,進(jìn)一步增強(qiáng)客戶端的訪問性能。如果有好的財(cái)力,還可以使用一些商業(yè)的CDN加速服務(wù)。
應(yīng)用Cookie的注意事項(xiàng)
Cookie的應(yīng)用要注意,要限制cookie的應(yīng)用域和應(yīng)用的目錄以及過期時(shí)間。不然如果用戶是第一次訪問的話,可能連一個(gè)小小的靜態(tài)圖片都要發(fā)送cookie到服務(wù)器,這樣增加了通信負(fù)載。另外要限制cookie的大小,一個(gè)3k的cookie能夠增加延遲達(dá)到80ms。
提高頁(yè)面速度
頁(yè)面由2-4個(gè)不同域名的服務(wù)器提供服務(wù)能夠提高速度,這個(gè)國(guó)外也有研究證明。比如主html文件由app.domain.com提供,樣式表由style.domain.com提供,圖片等由img.domain.com提供,這樣瀏覽器可以同時(shí)從多個(gè)服務(wù)器下載文件,速度就能夠上去。但是最好不要超過4個(gè)。
樣式表文件位置
把樣式表文件放在頁(yè)面的<head>,這樣能夠先讀取。因?yàn)樵趇e中有個(gè)樣式表的問題,樣式表如果沒有加載完會(huì)影響后面的html內(nèi)容的頁(yè)面顯示,因此雖然html文件都已經(jīng)在瀏覽器了,但是頁(yè)面還是顯示不出來。
把JavaScript移到html文件末尾
把JavaScript移到html文件末尾。為什么這么做呢,因?yàn)镴avaScript處理的過程中會(huì)阻塞后面的頁(yè)面顯示,并且也會(huì)使得http請(qǐng)求也被阻止。筆者的網(wǎng)站就有過這樣的例子,網(wǎng)站上放了一個(gè)合作方的JavaScript,結(jié)果每次訪問時(shí)候感覺頁(yè)面都停滯,用戶體驗(yàn)特別差,后來讓同事處理了一下,放到末尾等頁(yè)面加載完了再顯示在原有位置,一下子就好了。
盡量避免跳轉(zhuǎn)
盡量避免跳轉(zhuǎn)比如301和302。如果必須的話,對(duì)301和302的頁(yè)面添加過期頭。筆者原來的單點(diǎn)登錄就需要進(jìn)行跳轉(zhuǎn),后來改進(jìn)了不需要跳轉(zhuǎn),整體的速度效果就出來了。
移除重復(fù)的腳本
要移除重復(fù)的腳本,ie會(huì)對(duì)重復(fù)的腳本發(fā)起重復(fù)的http請(qǐng)求,大多數(shù)網(wǎng)站在運(yùn)營(yíng)一段時(shí)間都有可能出現(xiàn)這個(gè)情況,筆者的網(wǎng)站中就經(jīng)常有市場(chǎng)人員添加的重復(fù)的廣告腳本。
AJAX內(nèi)容
AJAX內(nèi)容也是可以進(jìn)行緩存的,同樣可以壓縮和緩存異步調(diào)用的xml、json等數(shù)據(jù)。
對(duì)爬蟲進(jìn)行限制
對(duì)爬蟲進(jìn)行限制,國(guó)內(nèi)的一些爬蟲非常厲害,并且不遵守robots規(guī)矩,經(jīng)常有反應(yīng)某某厲害爬蟲把網(wǎng)站搞癱的事件。怎么對(duì)爬蟲進(jìn)行限制呢,只能在web服務(wù)器上下功夫了,apache等服務(wù)器都能夠進(jìn)行限制,筆者的lighttpd限制10個(gè)并發(fā)的配置如下:
evasive.max-conns-per-ip = 10
web層的優(yōu)化目的就是極大的利用了瀏覽器的緩存特性,從而達(dá)到幾乎是本地訪問的速度,下圖是筆者訪問douban.com首頁(yè)的效果圖對(duì)比:

前一列數(shù)據(jù)是空的緩存所需要下載的文件大小和http請(qǐng)求數(shù)量,后面是真實(shí)訪問的帶cache的情況,效果特別明顯。http請(qǐng)求減少了95%,內(nèi)容cache了82%。
應(yīng)用程序?qū)觾?yōu)化
應(yīng)用服務(wù)器的優(yōu)化
Php的可以采用一些優(yōu)化手段比如Zend Optimizer、eAccelerator、MMCache、Zend Performance Suite等
Java的可以采用一些性能強(qiáng)的jdk、應(yīng)用服務(wù)器,對(duì)jdk參數(shù)進(jìn)行優(yōu)化等等
使用ETag
ETag就像版本控制服務(wù)器中的版本號(hào)一樣,每次更新后的ETag是不一樣的,而瀏覽器處理就類似版本服務(wù)器的客戶端一樣,先把版本號(hào)發(fā)到服務(wù)器請(qǐng)求。ETag的處理過程,先是Web服務(wù)器在響應(yīng)的http頭中發(fā)送ETag,比如這樣:
ETag: "1111-2222-3333"
Last-Modified: Thu, 07 Oct 2007 15:20:18 GMT
而瀏覽器如果再次請(qǐng)求該頁(yè)面就會(huì)發(fā)送類似如下的頭:
If-None-Match: "1111-2222-3333"
If-Modified-Since: Thu, 07 Oct 2007 15:20:18 GMT
此時(shí),如果該頁(yè)面沒有任何變更,則web服務(wù)器會(huì)響應(yīng)一個(gè)304的頭,并且不需要附帶頁(yè)面內(nèi)容給瀏覽器(即不需要再動(dòng)態(tài)生成頁(yè)面內(nèi)容),這樣就大大減少了服務(wù)器的處理和網(wǎng)路通信負(fù)載。
同步變異步
同步變異步,在web2.0網(wǎng)站中經(jīng)常有很復(fù)雜的處理,比如一個(gè)用戶的注冊(cè)還需要發(fā)郵件等操作,有時(shí)候可能還有其他的處理,這樣用戶的等待時(shí)間比較長(zhǎng),并且容易出現(xiàn)錯(cuò)誤。此種情況下,把其他處理變成異步的,從而直接把頁(yè)面盡快響應(yīng)給用戶。筆者的一個(gè)數(shù)據(jù)上傳的程序也是如此處理,一大堆數(shù)據(jù),上傳時(shí)間可能就1-2秒,而處理時(shí)間可能長(zhǎng)的需要接近10秒(需要在數(shù)據(jù)庫(kù)中進(jìn)行上千次的插入操作),而在應(yīng)用服務(wù)器容器內(nèi)處理耗時(shí)則更長(zhǎng),筆者后來改成異步處理以后,用戶滿意度則大幅上升。
使用緩存
還是緩存,可能的情況下盡量使用緩存,畢竟現(xiàn)在內(nèi)存非常便宜,用空間換取時(shí)間效率應(yīng)該是非常劃算的。尤其是對(duì)耗時(shí)比較長(zhǎng)的、需要建立網(wǎng)絡(luò)鏈接的,方法:采用memcached進(jìn)行數(shù)據(jù)庫(kù)或者常用數(shù)據(jù)的緩存;應(yīng)用數(shù)據(jù)庫(kù)緩沖池減少建立數(shù)據(jù)庫(kù)連接的時(shí)間
采用gzip壓縮動(dòng)態(tài)頁(yè)面
可能情況下,也可以采用gzip壓縮動(dòng)態(tài)頁(yè)面。如果服務(wù)器較多,cpu負(fù)載不高,則可以考慮對(duì)動(dòng)態(tài)頁(yè)面增加gzip壓縮功能
集群處理
訪問壓力大的時(shí)候,對(duì)應(yīng)用服務(wù)器采用集群處理。
應(yīng)用服務(wù)器的優(yōu)化主要是減少程序處理的時(shí)間,提高運(yùn)行效率。
數(shù)據(jù)庫(kù)優(yōu)化
這個(gè)議題跟具體數(shù)據(jù)庫(kù)關(guān)系比較大,議題也比較廣泛,筆者就只簡(jiǎn)要列舉一下:
設(shè)置專門的DBA,專門負(fù)責(zé)數(shù)據(jù)庫(kù)的安裝、優(yōu)化;對(duì)sql進(jìn)行優(yōu)化采用數(shù)據(jù)庫(kù)集群和復(fù)制功能分擔(dān)數(shù)據(jù)庫(kù)壓力。
其他優(yōu)化措施
網(wǎng)站的優(yōu)化涉及的方面比較多,其他方面涉及的還包括網(wǎng)站架構(gòu)、操作系統(tǒng)、服務(wù)器硬件、網(wǎng)絡(luò)設(shè)備、isp機(jī)房網(wǎng)絡(luò)等等的調(diào)優(yōu)。
工具
筆者用到的工具,都是firefox插件,所以firefox是必備的了:
1、LiveHTTPHeaders (http://livehttpheaders.mozdev.org/)
2、Firebug (http://getfirebug.com)
3、YSlow (http://developer.yahoo.com/yslow/),要先裝Firebug
4、Web Developer (http://chrispederick.com/work/web-developer/)
除了這些免費(fèi)的工具外,還可以采用一些商業(yè)的網(wǎng)站性能監(jiān)測(cè)服務(wù)。一般網(wǎng)站性能監(jiān)測(cè)服務(wù)商都會(huì)在不同的isp設(shè)置數(shù)據(jù)采集點(diǎn),然后會(huì)定期模擬瀏覽器的訪問對(duì)網(wǎng)站進(jìn)行訪問獲取各種數(shù)據(jù),比如dsn查詢時(shí)間、第一個(gè)包獲取時(shí)間、整個(gè)頁(yè)面加載時(shí)間等等,然后匯總到數(shù)據(jù)中心。數(shù)據(jù)中心則可以產(chǎn)生性能報(bào)表、不同時(shí)間的可訪問率、哪個(gè)isp容易出問題、發(fā)出警報(bào)等等。如果預(yù)算足夠的話,可以采用這個(gè)服務(wù)。國(guó)外的有keynote、ip-label等,功能比較齊全,但是服務(wù)費(fèi)用比較貴而且國(guó)內(nèi)的點(diǎn)比較少。國(guó)內(nèi)近些年也開始涌現(xiàn)出一些廠商,比如基調(diào)網(wǎng)絡(luò)。筆者使用的監(jiān)測(cè)系統(tǒng)的圖例:

筆者網(wǎng)站3年不同階段的優(yōu)化過程
優(yōu)化的原則是盡量不去優(yōu)化,在未發(fā)生性能問題的時(shí)候,沒有必要去專門考慮細(xì)節(jié)的性能問題,當(dāng)然大的結(jié)構(gòu)應(yīng)該是能夠適應(yīng)網(wǎng)站不斷發(fā)展變化的。筆者的網(wǎng)站近3年的優(yōu)化過程如下:
1、開發(fā)完成,剛上線的時(shí)候,不做優(yōu)化,用戶量少,用了3臺(tái)服務(wù)器。
2、10萬(wàn)用戶的時(shí)候,主要對(duì)sql進(jìn)行了優(yōu)化,還是3臺(tái)服務(wù)器。
3、10萬(wàn)用戶到100萬(wàn)的過程中,采用了AJAX等,因此開始關(guān)注JavaScript的優(yōu)化手段,訪問量也快速上去,因此對(duì)靜態(tài)文件進(jìn)行分離并優(yōu)化。服務(wù)器也進(jìn)行了擴(kuò)展,擴(kuò)展到5臺(tái)服務(wù)器。
4、100萬(wàn)-200萬(wàn)用戶,業(yè)務(wù)系統(tǒng)增加了很多,因此數(shù)據(jù)庫(kù)采用了復(fù)制,程序方面應(yīng)用了各種緩存處理,在數(shù)據(jù)庫(kù)和程序之間增加了memcached進(jìn)行數(shù)據(jù)緩存。
5、在200萬(wàn)用戶以上,主要在程序架構(gòu)上做文章,對(duì)某些服務(wù)使用了集群。另外為了監(jiān)測(cè)國(guó)內(nèi)不同城市、isp的網(wǎng)絡(luò)狀況,使用了商業(yè)化的網(wǎng)站性能監(jiān)測(cè)服務(wù)。