Web程序優化的最佳實踐(服務器篇)

【編者按】來自Yahoo!的Exceptional Performance團隊為我們帶來瞭改善Web性能的最佳實踐方案。為此,他們為此進行瞭 一系列的實驗、開發瞭各種工具、寫瞭大量的文章和博客並在各種會議上參與探討。最佳實踐的核心就是提高網站性能。通過各種努力,xcetional Performance團隊總結出瞭一系列可以提高網站速度的方法。可以分為 7 大類 34 條。包括內容、服務器、cookie、CSS、JavaScript、圖片、移動應用等七部分。本文為服務器端的優化實踐內容。

除瞭在網站在內容上的改進外(詳情可查看站長之傢前文:Web程序優化的最佳實踐(網站內容篇)),在網站服務器端上也有需要註意和改進的地方,它們包括:

1. 使用內容分發網絡

2. 為文件頭指定Expires或Cache-Control

3. Gzip壓縮文件內容

4. 配置ETag

5. 盡早刷新輸出緩沖

6. 使用GET來完成AJAX請求

1、使用內容分發網絡

用戶與你網站服務器的接近程度會影響響應時間的長短。把你的網站內容分散到多個、 處於不同地域位置的服務器上可以加快下載速度。但是首先我們應該做些什麼呢? 按地域佈置網站內容的第一步並不是要嘗試重新架構你的網站讓他們在分發服務器上 正常運行。根據應用的需求來改變網站結構,這可能會包括一些比較復雜的任務,如在 服務器間同步Session狀態和合並數據庫更新等。要想縮短用戶和內容服務器的距離, 這些架構步驟可能是不可避免的。

要記住,在終端用戶的響應時間中有 80%到 90%的響應時間用於下載圖像、樣式表、腳 本、Flash等頁面內容。這就是網站性能黃金守則。和重新設計你的應用程序架構這樣 比較困難的任務相比,首先來分佈靜態內容會更好一點。這不僅會縮短響應時間,而且 對於內容分發網絡來說它更容易實現。

內容分發網絡(Content Delivery Network,CDN)是由一系列分散到各個不同地理位 置上的Web服務器組成的,它提高瞭網站內容的傳輸速度。用於向用戶傳輸內容的服務 器主要是根據和用戶在網絡上的靠近程度來指定的。例如,擁有最少網絡跳數(network hops)和響應速度最快的服務器會被選定。 一些大型的網絡公司擁有自己的CDN,但是使用像Akamai Technologies,Mirror Image

Internet, 或者Limelight Networks這樣的CDN服務成本卻非常高。對於剛剛起步的企

業和個人網站來說,可能沒有使用CDN的成本預算,但是隨著目標用戶群的不斷擴大和 更加全球化,CDN就是實現快速響應所必需的瞭。以Yahoo來說,他們轉移到CDN上的網 站程序靜態內容節省瞭終端用戶 20%以上的響應時間。使用CDN是一個隻需要相對簡單地

修改代碼實現顯著改善網站訪問速度的方法。

2、為文件頭指定Expires或Cache-Control

這條守則包括兩方面的內容:

對於靜態內容:設置文件頭過期時間Expires的值為”Never expire”(永不過期) 對於動態內容:使用恰當的Cache-Control文件頭來幫助瀏覽器進行有條件的請求 網頁內容設計現在越來越豐富,這就意味著頁面中要包含更多的腳本、樣式表、圖片和 Flash。第一次訪問你頁面的用戶就意味著進行多次的HTTP請求,但是通過使用Expires 文件頭就可以使這樣內容具有緩存性。

它避免瞭接下來的頁面訪問中不必要的HTTP請求。Expires文件頭經常用於圖像文件,但是應該在所有的內容都使用他,包括腳本、樣式 表和Flash等。瀏覽器(和代理)使用緩存來減少HTTP請求的大小和次數以加快頁面訪問速度。Web服 務器在HTTP響應中使用Expires文件頭來告訴客戶端內容需要緩存多長時間。下面這個 例子是一個較長時間的Expires文件頭,它告訴瀏覽器這個響應直到 2010 年 4 月 15 日 才過期。

Expires: Thu, 15 Apr 2010 20:00:00 GMT

如果你使用的是Apache服務器,可以使用ExpiresDefault來設定相對當前日期的過期時 間。下面這個例子是使用ExpiresDefault來設定請求時間後 10 年過期的文件頭:

ExpiresDefault “access plus 10 years”

要切記,如果使用瞭Expires文件頭,當頁面內容改變時就必須改變內容的文件名。依Yahoo!來說我們經常使用這樣的步驟:在內容的文件名中加上版本號,如 yahoo_2.0.6.js。

使用Expires文件頭隻有會在用戶已經訪問過你的網站後才會起作用。當用戶首次訪問 你的網站時這對減少HTTP請求次數來說是無效的,因為瀏覽器的緩存是空的。因此這種 方法對於你網站性能的改進情況要依據他們”預緩存”存在時對你頁面的點擊頻率(”預緩存”中已經包含瞭頁面中的所有內容)。

Yahoo!建立瞭一套測量方法,我們發現所有的頁面瀏覽量中有 75~85%都有”預緩存”。通過使用Expires文件頭,增加瞭緩 存在瀏覽器中內容的數量,並且可以在用戶接下來的請求中再次使用這些內容,這甚至都不需要通過用戶發送一個字節的請求。

3、Gzip壓縮文件內容

網絡傳輸中的HTTP請求和應答時間可以通過前端機制得到顯著改善。的確,終端用戶的 帶寬、互聯網提供者、與對等交換點的靠近程度等都不是網站開發者所能決定的。但是 還有其他因素影響著響應時間。通過減小HTTP響應的大小可以節省HTTP響應時間。 從HTTP/1.1 開始,web客戶端都默認支持HTTP請求中有Accept-Encoding文件頭的壓縮格 式:

Accept-Encoding: gzip, deflate

如果web服務器在請求的文件頭中檢測到上面的代碼,就會以客戶端列出的方式壓縮響 應內容。Web服務器把壓縮方式通過響應文件頭中的Content-Encoding來返回給瀏覽器。 Content-Encoding: gzip Gzip是目前最流行也是最有效的壓縮方式。這是由GNU項目開發並通過RFC 1952來標準

化的。另外僅有的一個壓縮格式是deflate,但是它的使用范圍有限效果也稍稍遜色。

Gzip大概可以減少 70%的響應規模。目前大約有 90%通過瀏覽器傳輸的互聯網交換支持 gzip格式。如果你使用的是Apache,gzip模塊配置和你的版本有關:Apache 1.3 使 用mod_zip,而Apache 2.x使用moflate。 瀏覽器和代理都會存在這樣的問題:瀏覽器期望收到的和實際接收到的內容會存在不匹 配的現象。幸好,這種特殊情況隨著舊式瀏覽器使用量的減少在減少。Apache模塊會通 過自動添加適當的Vary響應文件頭來避免這種狀況的出現。

服務器根據文件類型來選擇需要進行gzip壓縮的文件,但是這過於限制瞭可壓縮的文件。 大多數web服務器會壓縮HTML文檔。對腳本和樣式表進行壓縮同樣也是值得做的事情, 但是很多web服務器都沒有這個功能。實際上,壓縮任何一個文本類型的響應,包括XML 和JSON,都值得的。圖像和PDF文件由於已經壓縮過瞭所以不能再進行gzip壓縮。如果 試圖gizp壓縮這些文件的話不但會浪費CPU資源還會增加文件的大小。

Gzip壓縮所有可能的文件類型是減少文件體積增加用戶體驗的簡單方法。

4、配置ETag

Entity tags(ETags)(實體標簽)是web服務器和瀏覽器用於判斷瀏覽器緩存中的內 容和服務器中的原始內容是否匹配的一種機制(”實體”就是所說的”內容”,包括圖 片、腳本、樣式表等)。增加ETag為實體的驗證提供瞭一個比使用”last-modified date

(上次編輯時間)”更加靈活的機制。Etag是一個識別內容版本號的唯一字符串。唯一 的格式限制就是它必須包含在雙引號內。原始服務器通過含有ETag文件頭的響應指定頁 面內容的ETag。

HTTP/1.1 200 OK

Last-Modified: Tue, 12 Dec 2006 03:03:59 GMT ETag: “10c24bc-4ab-457e1c1f”

Content-Length: 12195

稍後,如果瀏覽器要驗證一個文件,它會使用If-None-Match文件頭來把ETag傳回給原 始服務器。在這個例子中,如果ETag匹配,就會返回一個 304 狀態碼,這就節省瞭 12195 字節的響應。

GET /i/yahoo.gif HTTP/1.1

Host: us.yimg.com

If-Modified-Since: Tue, 12 Dec 2006 03:03:59 GMT If-None-Match: “10c24bc-4ab-457e1c1f”

HTTP/1.1 304 Not Modified

ETag的問題在於,它是根據可以辨別網站所在的服務器的具有唯一性的屬性來生成的。 當瀏覽器從一臺服務器上獲得頁面內容後到另外一臺服務器上進行驗證時ETag就會不 匹配,這種情況對於使用服務器組和處理請求的網站來說是非常常見的。

默認情況下, Apache和IIS都會把數據嵌入ETag中,這會顯著減少多服務器間的文件驗證沖突。 Apache 1.3 和 2.x中的ETag格式為inode-size-timestamp。即使某個文件在不同的服務 器上會處於相同的目錄下,文件大小、權限、時間戳等都完全相同,但是在不同服務器 上他們的內碼也是不同的。

IIS 5.0 和IIS 6.0 處理ETag的機制相似。IIS中的ETag格式為 Filetimestamp:ChangeNumber。用ChangeNumber來跟蹤IIS配置的改變。網站所用的不 同IIS服務器間ChangeNumber也不相同。 不同的服務器上的Apache和IIS即使對於完全 相同的內容產生的ETag在也不相同,用戶並不會接收到一個小而快的 304 響應;相反他 們會接收一個正常的 200 響應並下載全部內容。如果你的網站隻放在一臺服務器上,就 不會存在這個問題。但是如果你的網站是架設在多個服務器上,並且使用Apache和IIS 產生默認的ETag配置,你的用戶獲得頁面就會相對慢一點,服務器會傳輸更多的內容, 占用更多的帶寬,代理也不會有效地緩存你的網站內容。即使你的內容擁有Expires文 件頭,無論用戶什麼時候點擊”刷新”或者”重載”按鈕都會發送相應的GET請求。

如果你沒有使用ETag提供的靈活的驗證模式,那麼幹脆把所有的ETag都去掉會更好。 Last-Modified文件頭驗證是基於內容的時間戳的。去掉ETag文件頭會減少響應和下次 請求中文件的大小。微軟的這篇支持文稿講述瞭如何去掉ETag。在Apache中,隻需要在配置文件中簡單添加下面一行代碼就可以瞭:

FileETag none

5、盡早刷新輸出緩沖

當用戶請求一個頁面時,無論如何都會花費 200 到 500 毫秒用於後臺組織 HTML 文件。 在這期間,瀏覽器會一直空閑等待數據返回。在 PHP 中,你可以使用 flush()方法,它 允許你把已經編譯的好的部分 HTML 響應文件先發送給瀏覽器,這時瀏覽器就會可以下 載文件中的內容(腳本等)而後臺同時處理剩餘的 HTML 頁面。這樣做的效果會在後臺 煩惱或者前臺較空閑時更加明顯。

輸出緩沖應用最好的一個地方就是緊跟在<head />之後,因為 HTML 的頭部分容易生成 而且頭部往往包含 CSS 和 JavaScript 文件,這樣瀏覽器就可以在後臺編譯剩餘 HTML 的

同時並行下載它們。 例子:

<!– css, js –>

</head>

<?php flush(); ?>

<body>

<!– content –>

為瞭證明使用這項技術的好處,Yahoo!搜索率先研究並完成瞭用戶測試。

6、使用GET來完成AJAX請求

Yahoo!Mail團隊發現,當使用XMLHttpRequest時,瀏覽器中的POST方法是一個”兩步走” 的過程:首先發送文件頭,然後才發送數據。因此使用GET最為恰當,因為它隻需發送 一個TCP包(除非你有很多cookie)。IE中URL的最大長度為 2K,因此如果你要發送一個超過2K的數據時就不能使用GET瞭。 一個有趣的不同就是POST並不像GET那樣實際發送數據。根據HTTP規范,GET意味著”獲 取”數據,因此當你僅僅獲取數據時使用GET更加有意義(從語意上講也是如此),相反,發送並在服務端保存數據時使用POST。

延伸閱讀:

  • Web程序優化的最佳實踐:JavaScript和CSS篇
  • Web程序優化的最佳實踐:Cookie、圖片及移動應用篇