案例:varnish对某个动态页面(a.jsp)进行了缓存,且指定缓存时长为5分钟。如果在这5分钟内a.jsp的数据发生了变化,访问时仍会显示旧数据。直到缓存到期后varnish重新缓存才会显示新数据。这就导致页面不能及时显示更新信息。而且由于缓存时长只是一个估计值,如果设定的太长,则不能及时显示新数据,如果设定的太短,则可能浪费资源。
varnish缓存也可以通过后台管理手动执行命令进行清除,但这显然也不够智能。如果我们能够通过程序自动清除缓存就好了!比如我们在后台添加商品的时候对varnish缓存的商品列表进行清除,再次加载商品列表页面时varnish找不到缓存就会重新请求并缓存新的页面。此时的商品列表就是最新的了。
下面用一个简单的java程序实现对varnish缓存的清除。
首先,在varnish配置文件(默认为default.vcl)中对a.jsp页面进行缓存配置。
sub vcl_recv {
……其他配置信息
if (req.url ~ "^.*/a.jsp$") {
return (lookup);
}……其他配置信息
}
sub vcl_fetch {
……其他配置信息
if(req.url ~ "^.*/a.jsp$") {
set beresp.ttl = 5m;
return (deliver);
}……其他配置信息
}
其次,在varnish配置文件中进行刷新缓存的处理。
#允许刷新缓存的规则
acl purgeallow {
"127.0.0.1";
"172.16.15.110";//这个IP地址也可以发起刷新请求
}sub vcl_recv {
if (req.request == "PURGE") {
if (!client.ip ~ purgeallow) {
error 405 "Not allowed";
}
#转到hit或者miss处理
return (lookup);
}}
sub vcl_hit {
#刷新缓存的请求操作,设置TTL为0,返回处理结果代码
if (req.request == "PURGE") {
set obj.ttl = 0s;
error 200 "Purged";
}
std.log("url hit! the url="+req.url);
#缓存服务器命中后(查找到了)
return (deliver);
}
sub vcl_miss {
#刷新缓存的请求操作
if (req.request == "PURGE") {
error 404 "Not in cache";
}
std.log("url miss! the url="+req.url);
#缓存服务器没有命中(去后台服务器取)
return (fetch);
}
最后,就是写个java程序进行测试了。
import java.io.IOException;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpMethodBase;
public class PurgeVarnish {
public void purge(String url){
HttpClient client = new HttpClient();
HttpMethod method = new PurgeMethod(url);
//添加头信息告诉服务端可以对Response进行GZip压缩。
//我在varnish配置文件的vcl_hash函数中对Accept-Encoding进行了hash,
//如果请求里面不带Accept-Encoding信息头的话,就找不到varnish中的缓存,导致无法清除缓存。
//vcl_hash函数中对Accept-Encoding进行了hash是因为有些浏览器可能不支持压缩,
//如果他们找到的缓存是被压缩过的,就会导致浏览器无法正确解析返回内容。
method.setRequestHeader("Accept-Encoding", "gzip, deflate");
try {
int status = client.executeMethod(method);
System.out.println("status==="+status);
} catch (IOException e) {
e.printStackTrace();
}finally{
method.releaseConnection();
}
}
public static void main(String[] args) {
PurgeVarnish purgeVarnish = new PurgeVarnish();
purgeVarnish.purge("http://172.16.15.111:1111/a.jsp");
}
}
class PurgeMethod extends HttpMethodBase {
public PurgeMethod() {
super();
setFollowRedirects(true);
}
public PurgeMethod(String url) {
super(url);
setFollowRedirects(true);
}
@Override
public String getName() {
return "PURGE";
}
}
注意我在method.setRequestHeader("Accept-Encoding", "gzip, deflate");这一行上面添加的注释。如果你不想添加这个信息头,只要确保varnish配置文件的val_hash函数中没有对Accept-Encoding进行hash即可。
好了,下面怎么测试就不用说了吧。