HTTP緩存(轉帖)

 

Config HTTP Header For Better Client Performance

網站的性能(Performance)要考慮兩方面,一方面是在Server端的運行效率,另一方面是在Client端感受到的效率。不要以爲Server端效率高這個網站或者服務給用戶的體驗就是高效的,如果不考慮影響Client Performance的因素,Server端跑得再快用戶也可能感覺慢得和牛一樣。

Yahoo的哥們做的研究真不是蓋的,他們還寫了本書《High Performance Web Sites》詳細介紹如果提高Client Performance。公司內部也有一個Team做這方面的事情,聽過他們的培訓,和Yahoo說的差不多,所謂英雄所見略同。

給靜態資源(HTML文件,圖片文件等)的Repsone加上Expires/Cache-Control Header是很有效的一招。如果HTTP Response中有Expires這樣的Header的話,瀏覽器會Cache這個資源,理想狀況下(注意,只是理想狀況),在Expire Date之前,不會再發HTTP請求給Server要這個資源,不過Expires的值只能是一個固定日期,比如“Thu 27 Nov 2008 07:00:00 GMT”,不能是一個類似“從現在開始之後10年”這樣一個隨機浮動的值,如果要這樣的效果,可以用Cache-Control這樣的Header,如果HTTP Resposne中有這樣的Header:“Cache-Control: max-age = 100”,表示這個資源在cache中的最大壽命是100秒。一般說來這種靜態文件永遠不應該過期,如果真的要給這個Cache加上一個期限,那我希望是——一萬年,“Cache-Control: max-age = 315360000000”Smile

其實就應該給Expires設一個永遠不會過期的時間,比如你現在有一個文件叫logo.gif,需要用一個新的logo的時候,你不要去覆蓋原來的文件,而把新的logo存成logo_v2.gif,讓相關網頁引用新的logo_v2.gif,這樣可以讓新老網頁同時工作,實在犯不上爲了節省存儲空間覆蓋原有文件。

對Apache服務器,使用mod_expires,在httpd.conf或者.htaccess中加上

<FilesMatch "//.(ico|gif|jpg|html)$">
ExpiresDefault "access plus 10 years"
</FileMatch>

對於IIS 6(IIS 7還不清楚),通過IIS Manager可以通過GUI添加Expires/Cache-Control,通過命令行修改就麻煩一點了。 

首先要到IIS的AdminScripts目錄下去找到adsutil.vbs文件。

cd C:/Inetpub/AdminScripts

比如我們要給根目錄下的imags目錄添加Expires/Cache-Control,先要在metabase中給它加一個節點

cscript adsutil.vbs create W3SVC/1/root/images "IisWebVirtualDir"

如果希望訪問images目錄下的文件獲得Cache-Control: max-age=60,就這樣

csript adsutil.vbs set W3SVC/1/root/images/HttpExpires "D, 0x3c"

如果希望訪問images目錄下的文件獲得“Expires: Thu 27 Nov 2008 07:00:00 GMT”,就這樣

csript adsutil.vbs set W3SVC/1/root/images/HttpExpires "S, Thu 27 Nov 2008 07:00:00 GMT"

還有,同一個HTTP Response中可以同時有Expires和Cache-Control,但是Cache-Control權限比Expires大,會override它的。

HTTP的Response中還會有另外一個Header叫Last-Modified,比如“Last-Modified:  Thu, 06 Apr 2006 21:17:12 GMT”,瀏覽器訪問一個URI得到這樣的Resposne之後,就知道這個資源最後一次的修改時間,下次需要再次獲得這個資源的時候,會發一個Request給Server,不過這個Request中有一條“If-Unmodified-Since: Thu, 06 Apr 2006 21:17:12 GMT”,如果在Server端在這個日期之後對這個資源進行了修改,就會照常返回這個資源給Client端,但是如果沒有修改,就會返回一個304 (Not Modified) Response而不返回資源,告訴Client端:“這個資源從上次給你之來從來沒改過,你放心用你Cache中的好了。” 一個304 Response比一個靜態資源通常小多了,這樣就節省了網絡帶寬。

圖像099

讓我們回過頭來比較一下Expires和Last-Modified這兩個東西,似乎Last-Modified比不上Expires,因爲雖然它能夠節省一點帶寬,但是還是逃不掉髮一個HTTP請求出去,而Expires卻使得瀏覽器乾脆連HTTP請求都不用發,豈不痛快!那還要Last-Modified這個物體幹什麼?理想狀況的確是這樣,不過當用戶在IE或者Firefox裏面按F5或者點擊Refresh按鈕的時候(不是在URL欄裏重新輸入一遍URL然後回車),就算對於有Expires的URI,一樣也會發一個HTTP請求出去,所以,Last-Modified還是要用的,而且要和Expires一起用。

除了Last-Modified,HTTP Response中還可能有另外一個Header: ETag,使得Server上的靜態資源有點“版本控制”的味道Smile 假如HTTP Response中包含“ETag: "abcdefg1234:0001"”,等於告訴Client端,你拿到的這個版本的資源有個ID,叫做abcdefg1234:0001,下次需要發Request索要同一個URI的時候,在Request裏面加一條“If-None-Match: "abcdefg1234:0001"”,好,Server端做了一些修改,下次這個Client再來了一個請求,但是這時候資源已經改了,所以返回這個新資源,還有新的tag “ETag: "abcdefg4567:0001"”(這個etag我是胡寫的),這樣,Client端等於Cache了兩份,在需要索要這個資源的時候,可以包含這樣的Header: “If-None-Match: "abcdefg1234:0001" "abcdefg4567:0001"”,這樣,即使Server端頭腦發熱,把這個資源Roll back回原來的版本,依然會返回304 (Not Modified) Response,因爲它知道Client端Cache着以前的版本呢,這點功能是Last-Modifed/If-Not-Modified沒法做到的。

不過ETag/If-None-Match這點功能實在是個雞肋,首先,Server端的資源不大可能Roll Back,更重要的是,有可能造成Client Performance下降。對於只有一個Server的網站,沒什麼問題,但是現在稍微上點規模的網站都需要Scale Out,也就是說需要前端一個Load Balancer,後面接多臺Server來處理請求,俗稱Cluster,既然是Cluster,那麼每個請求到底返回什麼結果應該和分配到哪個Server無關,不過這個ETag可能就壞事了。假如用戶的第一次請求分配給Server A,返回“ETag: "abcdefg1234:0001"”,但是第二次請求分配給了Server B,Server B上這個資源和Server A上的一模一樣,但是計算出這個資源的ETag是"abcdefg1234:0002",這下麻煩了,雖然內容一樣,但是ETag不匹配,還是浪費了帶寬把資源發送了一遍,冤枉啊!而事實上,不同Server上的ETag很有可能不同,對於Apache,ETag的計算考慮了inode,對於IIS,ETag考慮了metabase的修改版本,要保證不同server上的這些信息一致,有點小難。不過不是有Last-Modified/If-Not-Modified嗎?Server端看到If-Modified-Since,對照一下時間對得上,不管If-None-Match,可以直接發回304(Not Modified)呀,很不幸,RFC2616對這種情況做了規定,如果既有If-None-Match又有If-Modified-Since,除非兩者不衝突,不然不會返回304。

圖像101

所以說ETag就是一個害人精,按照Yahoo的建議,別費勁想辦法同步不同Server上的ETag了,乾脆就把ETag刪除得了(缺省,Apache和IIS都是有ETag的),我Sniff了一下Yahoo的若干網頁返回HTTP Response,的確沒有ETag,人家的確是知行合一Smile 

對於Apache,在httpd.conf或者.htaccess中加一行就搞定了:

FileETag none

對於IIS 6,可就有點費勁了,首先,似乎沒有辦法通過Config來把ETag去掉,查了很多資料,問了很多人,似乎能夠去掉ETag的辦法只有寫一個ISAPI Filter來弄,Sniff了一下Microsoft的幾個網頁的結果顯示ETag都穩當當的存在,估計目前真的沒有什麼好方法。

只好退而取其次,保證不同Server上的ETag一致了。 IIS對Etag的計算算法是ETag = {Filetimestamp:ChangeNumber}, Filetimestamp保持一致沒什麼問題,ChangeNumber是metabase的change number,就有點難保證Cluster中每個Server都一樣了,所以,乾脆就把它設成固定值好了,這個連接告訴我們該怎麼辦,很可惜,沒有找到徹底刪除ETags的配置。

發佈了30 篇原創文章 · 獲贊 2 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章