Squid對動態(tài)頁面Cache的相關(guān)須知
使用Squid做代理服務(wù)器,靜態(tài)頁面還比較簡單,但動態(tài)頁面則并沒有那么簡單了。尤其現(xiàn)在大部分網(wǎng)頁都是動態(tài)頁面,運維人員在架設(shè)Squid的時候需要對這方面的配置留心。下面概述一下Squid對動態(tài)頁面進(jìn)行cache的時候需要考慮的方面。
1 被cache的頁面必須對所有用戶顯示的內(nèi)容都是一致的。
如果同一個URL(包括參數(shù))對不同用戶如果顯示不同的內(nèi)容,那么cache它會使一些用戶看到其它用戶才能看到的內(nèi)容。
(我***步緩存的是訪問量***的閱讀帖子的頁面,但是頁面上原來有非常復(fù)雜的權(quán)限判斷,針對這種情況,考慮到大部分信息在短期內(nèi)基本是變化不大的,只好將用戶基本信息寫入cookie,使用前端的js來控制。雖然這樣會導(dǎo)致限制不嚴(yán)格現(xiàn)象,但是因為畢竟不是商業(yè)應(yīng)用,這些損失和性能相比還是可以接受的)
2 被cache的動態(tài)頁面不能啟動一個session。
因為通常session都是用cookie實現(xiàn),啟動一個session意味著服務(wù)器會發(fā)送一個Set-Cookie的HTTP頭,squid把這樣的頁面cache之后,會造成所有后續(xù)的訪問用戶都在自己的瀏覽器里設(shè)置相同的cookie,這會造成嚴(yán)重的后果。所有設(shè)置cookie操作的頁面都有此類問題,即使不是啟用一個session。所以,這類頁面是絕對不能cache的。但是對包含在一個已啟動的session里的頁面進(jìn)行cache則不會有這個問題。
(我基本上沒有用到session,set-cookie(服務(wù)器端的)在需要緩存的這個頁面也沒有,只有一個為了配合廣告活動增加的用js來set- cookie,所以也沒有問題)
3 用戶的訪問頻度必須遠(yuǎn)遠(yuǎn)超過頁面內(nèi)容的更新頻度,否則cache的意義不大。
(這個頁面每天的pv超過100萬,所以還是想當(dāng)有必要的 )
另外,cache動態(tài)頁面以后,由于squid會攔截用戶的請求,應(yīng)用程序服務(wù)器收不到被攔截的請求,必須保證這不會影響應(yīng)用的處理邏輯。
使用squid來cache動態(tài)頁面有兩種方式,一種是在頁面里動態(tài)生成幾個HTTP頭:其中一個是Last-Modified,這個頭表示頁面上次修改的時間,一般訪問靜態(tài)頁面時,apache會根據(jù)靜態(tài)文件的一個上次修改時戳來設(shè)置這個屬性。
(我們采用了這個last-modifyed 頭來進(jìn)行,然后在文件會發(fā)生變化時通知squid這樣可以提高squid的緩存命中率)
另一個是Expires或者Cache-Control。Expires代表頁面將在該時間之后過期,squid會從后端的應(yīng)用服務(wù)器重新獲取頁面。Cache-Control則通過一個max-age屬性來告訴squid和瀏覽器這個頁面從Last-Modified開始的生存時間。Expires和Cache-Control只設(shè)置一個就可以。
Last-Modified和Expires的時間格式是,Wed, 14 May 2003 13:06:17 GMT。注意生成這個時間時一定要轉(zhuǎn)換成GMT時間,這樣才能使互聯(lián)網(wǎng)的全球用戶都能正確識別。max-age的時間是一個整數(shù),單位是秒。詳細(xì)的文檔請參考RFC2616。這幾個HTTP頭必須在所有頁面內(nèi)容輸出之前進(jìn)行設(shè)置,否則應(yīng)用程序會報錯。
php的例子如下:
# Last-Modified時間設(shè)置為當(dāng)前時間
header("Last-Modified: " . gmdate("D, d M Y H:i:s" . " GMT";
# Expires時間設(shè)置為1小時后
header("Expires: " . gmdate("D, d M Y H:i:s", time() + 3600) . " GMT";
第二種cache方式是使squid強制cache某些指定的頁面,而不管頁面中是否有前面提到的那幾個HTTP頭。相應(yīng)的配置參數(shù)舉例如下:
#下面兩行表示凡是帶參數(shù)(含有?)的URL就不cache,必須注釋掉。 #acl QUERY urlpath_regex cgi-bin \? #no_cache deny QUERY #下面兩行創(chuàng)建一個acl,它匹配兩個jsp頁面 acl CACHABLE_PAGES urlpath_regex ^/topic/readSub\.jsp acl CACHABLE_PAGES urlpath_regex ^/topic/listFrame\.jsp #下面一個acl匹配所有的動態(tài)頁面 acl NONE_CACHABLE_PAGES urlpath_regex \? \.jsp #允許cache兩個jsp頁面 no_cache allow CACHABLE_PAGES #禁止cache其它的jsp頁面 no_cache deny NONE_CACHABLE_PAGES #下面幾行設(shè)置頁面cache的時長,***行cache一天,第二行cache兩分鐘 refresh_pattern ^http://post.mop.com/topic/readSub\.jsp 1440 0% 1440 ignore-reload refresh_pattern ^http://post.mop.com/topic/listFrame\.jsp 2 0% 2 ignore-reload
對于顯示帖子內(nèi)容的頁面,當(dāng)用戶回復(fù)之后,帖子內(nèi)容就改變了,為了實時刷新頁面,可以在用戶改變帖子內(nèi)容之后,打開一個tcp連接到squid,發(fā)送一個PURGE指令,就可以將指定的URL過期,squid會重新到服務(wù)器上抓***頁面。
相應(yīng)頁面中需要增加:
Date last_modified_time = s.getLastReplyTime();
String modifySince=request.getHeader("If-Modified-Since";
SimpleDateFormat tempSdf=new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z",new java.util.Locale("en");
try{
Date modifySinceDate=tempSdf.parse(modifySince);
if (!modifySinceDate.before(last_modified_time)){
response.sendError(HttpServletResponse.SC_NOT_MODIFIED);
return;
}
}catch (Exception e){
out.println("";
}
long last_modified = last_modified_time.getTime();
response.setDateHeader("Last-Modified",last_modified);
—————————————————————————————-
察看cache命中率等信息,可以用如下命令:
/data/squid/bin/squidclient -p 80 cache_object://localhost/info
其中的如下信息比較重要:
Cache information for squid: Request Hit Ratios: 5min: 41.5%, 60min: 40.1% Byte Hit Ratios: 5min: 52.3%, 60min: 50.8% Request Memory Hit Ratios: 5min: 27.7%, 60min: 30.7% Request Disk Hit Ratios: 5min: 38.3%, 60min: 39.2% Storage Swap size: 1886720 KB Storage Mem size: 39452 KB Mean Object Size: 50.85 KB Requests given to unlinkd: 1685
參考:http://www.708034.cn/?p=298
【編輯推薦】