Purging and banning
一种非常有效的提升命中率的方法是提升ttl,但是,你也知道,对有些网站(像Twitter这样的社交网站),服务内容过于陈旧对企业是不利的。
解决的办法就是当有新内容的时候通知varnish。这个可以通过三种方法来完成:http清除、取缔或者强制缓存不命中。首先先来看一下如何通过http清除缓存:
HTTP Purging
这种方法是当你从缓存中检出一个对象,并删除它和它相关的内容。一般情况下这是通过HTTP协议的PURGE的方法来实现的。
HTTP的PURGE与HTTP的GET请求类似,除了method是PURGE。其实你可以通过任何你喜欢的方式来调用,但是很多人都喜欢使用purge。例如Squid就支持相同的机制。为了在varnish中支持清除操作,你需要在vcl中这样写:
acl purge {
"localhost";
"192.168.55.0"/24;
}
sub vcl_recv {
# allow PURGE from localhost and 192.168.55...
if (req.method == "PURGE") {
if (!client.ip ~ purge) {
return(synth(405,"Not allowed."));
}
return (purge);
}
}
你可以看到,我们使用了一个新的action——return(purge)。这个会结束vcl_recv的执行,并跳转到vcl_hash。这就像我们处理一个普通的请求一样。当vcl_hash调用return(lookup),varnish将会清除这个对象,然后调用vcl_purge。这里你可以添加任何你想要varnish执行的特定的动作,当对象被清除后。
因此,对于example.com为了清除前端页面缓存,他们将会这样请求varnish:
PURGE / HTTP/1.0
Host: example.com
varnish将会清除前端页面缓存。这将会移除所有在Vary中定义的变种。
取消缓存 Bans
还有另外一种去掉缓存的方式是:取消缓存。你可以把 “取消缓存”理解为对已经缓存的对象的一种过滤器。你可以从你的缓存中把某些内容取消缓存
。你可以基于任何已有的元数据把具体内容取消缓存。取消缓存只对那些已经被缓存的对象有效,对新增加的对象和正在处理的对象是无效的。
取消缓存是Varnish内置的功能,只能在Varnish的命令行接口(CLI)执行。如果我想对example.com域名下的所有.png后缀的对象取消缓存,这种情况下可以执行下面的命令:
ban req.http.host == "example.com" && req.url ~ "\\.png$"
真的很强大,对吧?
当我们缓存一个对象的时候,需要选择一个取消缓存规则。但是在返回数据给客户端之前 一个对象只会匹配最新的取消缓存规则.
取消缓存规则在匹配 obj.* 这类对象的时候,也会通过一个叫做作ban lurker的后台进程处理。ban lurker会将对象放到堆栈中并尝试匹配这些对象,然后从堆栈中删除匹配的对象。值得高兴的是ban lurker可以通 ban_lurker_sleep 来控制。也可以通过将参数 ban_lurker_sleep 设置为0来关闭ban lurker。
如果取消缓存规则比缓存中缓存时间最长的对象都陈旧,它就会直接被删除了。如果你的很多对象的TTL值设置的很大,而且不经常被访问,你可能会积累了很多取消缓存规则。这可能会增加CPU的使用率从而影响性能。
你也可以通过HTTP添加取消缓存规则。要做到这点你需要配置VCL:
sub vcl_recv {
if (req.method == "BAN") {
# Same ACL check as above:
if (!client.ip ~ purge) {
return(synth(403, "Not allowed."));
}
ban("req.http.host == " + req.http.host +
" && req.url == " + req.url);
# Throw a synthetic page so the
# request won't go to the backend.
return(synth(200, "Ban added"));
}
}
这段VCL配置是让Varnish能处理一个HTTP的BAN方法,对请求的URL包括域名添加取消缓存规则。
ban lurker可以帮助你保持ban列表在一个可管理的范围之内,因此我们建议你不要在你的bans中使用 req.*,因为请求的对象在ban lurker中是不可用的。
你可以照着下面的模板让取消缓存规则对于ban lurker
更加友好:
sub vcl_backend_response {
set beresp.http.url = bereq.url;
}
sub vcl_deliver {
unset resp.http.url; # Optional
}
sub vcl_recv {
if (req.method == "PURGE") {
if (client.ip !~ purge) {
return(synth(403, "Not allowed"));
}
ban("obj.http.url ~ " + req.url); # Assumes req.url is a regex. This might be a bit too simple
}
}
为了检查当前的ban列表,可以在命令行中使用ban.list
命令,这将会为你展示当前所有bans的状态:
0xb75096d0 1318329475.377475 10 obj.http.url ~ test
0xb7509610 1318329470.785875 20G obj.http.url ~ test
这个取消缓存规则列表包含取消缓存规则的ID和创建取消缓存规则的时间戳。中间一列是当前已经被取消缓存的对象的总数,如果这个数值后面有个‘G’表示这个取消缓存规则已经失效了。最后列出的取消缓存规则列表中有些重复的取消缓存规则也会标记为‘G’,为了以后优化,这种取消缓存规则也会保存在列表中。
强制命中但不缓存
最后一种删除缓存更新对象内容的方法是在单个请求中强制 hash miss。如果你设置 ‘req.hash_always_miss’为true,Varnish将不会在缓存中查找当前对象,直接强制从后端服务器获取内容。这样就会返回给客户端最新的内容,替代当前缓存中的内容。缓存中的旧的内容会一直留在缓存中直到TTL过期,或者被其他一些机制删除。