varnish作為緩存服務提供者,本身沒有內容,所有內容都是從後端的服務器或其它緩存服務器上取過來的。當varnish收到這些內容之後,需要根椐一定的策略確定是否緩存它,如果需要緩存,還需要確定可以緩存的時間。
1、varnish緩存策略
缺省是根椐後端返回的http狀態碼決定是否緩存。可以緩存的狀態碼如下:
200
203
300
301
302
410
404
varnish現在還不支持ranges請求,所以不會緩存206狀態的結果。
管理員可以在vcl的配置文件中的vcl_fetch部分,加入自已的緩存策略,方法是修改beresp.cacheable變量。下面的例子,看後端返回中如果設置了cookie,則不緩存:
sub fetch {
if (beresp.http.Set-Cookie) {
set beresp.cacheable = false;
}
}
2、緩存時間的計算方法
缺省的緩存時間計算方法如下:
. 先根椐max-age確定緩存時間
看返回頭中的Cache-Control頭中,有沒有指定s-maxage或max-age信息,另外,如果後端是一個緩存服務器,它還會指定一個age頭,表明已經緩存過的時間,這樣需要減去age頭指定的時間,計算出對應的緩存時間。
例1 只有max-age,沒有age
CacheControl: max-age=86400
緩存時間:86400秒,即一天
例2 同時有max-age和age信息
CacheControl: max-age=86400
Age: 6400
緩存時間:86400 – 6400 = 80000秒
. 如果沒有max-age信息,則根椐Expires頭部計算緩存時間
先看有沒有Date頭,
如果沒有Date頭
看expires指定的時間是否小於收到數據的時間
小於,表明從後端取得內容已經過期,緩存時間為0,不緩存
>=,則緩存到Expires指定的時刻再過期
如果有Date頭
看Expires指定的時間是否小於Date指定的時間
小於,取到已經過期的內容,緩存時間為0,不緩存
>=,則看Date時間跟取到內容的時間差別(判斷本機和後端的時鐘差異)
小於clock_skew(缺省是10秒,管理員可以設置別的數值),以本機時間為准
看Expires指定的時間是否小於收到數據的時間
小於,表明從後端取得的內容已經過期,緩存時間為0,不緩存
>=,則緩存到Expires指定的時刻再過期
>= clock_skew,以後端的時間為准
緩存時間為Expires – Date的差值
. 如果既沒有max-age信息,又沒有指定Expires過期信息
則按default_ttl(缺省是2分鐘,管理員可以設置成別的數值)設置緩存時間。
管理員可以在vcl的配置文件中的vcl_fetch部分,手工指定緩存時間,方法是修改beresp.ttl變量。下面的例子,將緩存時間設置成20分鐘(1200秒):
set beresp.ttl = 1200s;
3、給用戶返回已經過期的對象
varnish內部有一個grace模式。當後端不可用,或者已經向後端發過更新請求的情況下,別的客戶再請求這個對象時,會收到已經過期的版本,當然過期的時間在可接受的范圍內。
varnish缺省可接受的過期時間范圍是不超過10秒,可以修改params中的default_grace參數。修改這一數值,但這樣的改法相當於改了全局的參數,適應於所有請求。
如果想只修改特定的url對應的對象的grace時間范圍,則需要修改vcl配置,改兩個地方。首先需要修改vcl_recv過程,在收到用戶請求時指定可以接受過期對象的過期時間范圍。其次需要修改vcl_fetch過程,從後端取到內容時,設置對象過期後還可以保留的時間,這樣以便在過期後不會立即被後台線程清理掉。
下面的例子針對特定的請求,將接受對象的grace時間設置為2分鐘
sub vcl_recv {
set req.grace = 2m;
}
sub vcl_fetch {
set beresp.grace = 2m;
}
4、varnish對象過期之後的更新說明
對象過期之後,過了grace時間,就會被後台線程清理掉。下一次用戶再去訪問的時候,會從後端重新抓取該對象。更合適的方法是發一個ims請求,如果後端對應的對象沒有更新就不抓。這一點squid處理得比varnish好。希望以後的版本能改進這一塊。
參考信息:
/bin/varnishd/cache_center.c的cnt_fetch函數
/bin/varnishd/rfc2616.c的RFC2616_Ttl函數
/bin/varnishd/cache_hash.c的HSH_Lookup函數