![Varnish 禁令的范围和效用](https://linux22.com/image/755954/Varnish%20%E7%A6%81%E4%BB%A4%E7%9A%84%E8%8C%83%E5%9B%B4%E5%92%8C%E6%95%88%E7%94%A8.png)
我需要使与已删除/取消发布或已更新的资源相关的一组 URL 的缓存失效。例如,如果我的资源 UUID 是,1234abcd
我想使 下的所有缓存派生项失效/resource/1234abcd/*
。
我知道 Varnish 无法使用 来实现这一点purge
,但可以使用 bans 来实现。不过,我很难理解 bans 究竟是如何工作的。
例如,如果我更新资源1234abcd
并禁止其所有衍生品,我假设下一个客户端请求将/resource/1234abcd/derv1
是新的后端获取,并且新资源将被缓存。我是否会拥有同一衍生品的两个版本,一个被禁止,一个不被禁止(直到旧版本过期并且最终其禁令也过期)?如果我的资源的到期日期很长,我可能会积累大量缓存资源的禁令,我宁愿立即清除这些禁令。
在软件设计层面上,保留无法访问的资源而不是实现基于正则表达式的清除(这似乎更容易管理)有什么用处?
另外,我在开发环境中实施了禁令,我发现禁令在提出请求后一分钟左右才会生效。这与禁令潜伏者或其他时间设置有关吗?
谢谢。
答案1
禁令和禁令名单
Varnish 中的禁令是基于所谓的禁令名单. 禁止列表中的项目符合特定标准,理想情况下与缓存对象的属性相匹配。
这禁止潜伏者,一个监视禁令列表的单独线程负责删除匹配的对象。
禁止和正则表达式 URL 匹配
大多数情况下,您会想要匹配需要无效的 URL 模式。
一个简单的方法是发布以下禁令:
req.http.host == example.com && req.url ~ /resource/1234abcd/.*
这个例子的问题是请求范围:封禁潜伏者只能访问对象及其属性。请求信息不属于其中,因为对象仅包含响应信息。
在这种情况下,潜伏者不会匹配禁令列表中的项目,并且该项目将保留在缓存中,直到下一个用户点击匹配的 URL。这是不高效的。
适合潜伏者的禁令
我们用来绕过这些范围限制的一个技巧是添加主持人&网址信息以进行响应。
具体操作如下:
sub vcl_backend_response {
set beresp.http.url = bereq.url;
set beresp.http.host = bereq.http.host;
}
sub vcl_deliver {
unset resp.http.url;
unset resp.http.host;
}
然后您可以运行以下禁令:
obj.http.host == example.com && obj.http.url ~ /resource/1234abcd/.*
潜伏者将能够匹配这些属性,并将从缓存中远程获取匹配的对象,而无需发出请求。
潜伏者什么时候从缓存中移除对象?
二进制varnishd
文件有几个运行时设置,这些设置会影响禁令潜伏者处理禁令的方式:
- ban_lurker_age:封禁潜伏者会忽略封禁,直到封禁时间已经这么久
- ban_lurker_sleep:禁令潜伏者在检查一批禁令清单项目后会睡多久
- ban_lurker_batch:潜伏者在重新进入睡眠状态之前处理的封禁次数
如何发布禁令
有三种方法可以发出禁令:
- 通过 VCL 中定义的 HTTP 调用
- 通过
varnishadm
本地二进制文件 - 通过遥控器命令行界面通过 TCP/IP 进行呼叫
以下是一个varnishadm
例子:
varnishadm ban obj.http.host == example.com '&&' obj.http.url '~' '\\.png$'
有关遥控器的更多信息命令行界面致电,请查看:http://varnish-cache.org/docs/6.0/reference/varnish-cli.html#varnish-command-line-interface
这是一个HTTP例子:
acl purge {
"localhost";
"192.168.55.0"/24;
}
sub vcl_recv {
if (req.method == "PURGE") {
if (!client.ip ~ purge) {
return(synth(405,"Not allowed."));
}
if(req.http.x-purge-regex) {
ban("obj.http.host == " + req.http.host +" && obj.http.url ~ " + req.http.x-purge-regex);
return(synth(200, "Purged."));
}
return (purge);
}
}
在此HTTP例如,我们结合清除和禁止。
定期清除由...发出卷曲看起来是这样的:
curl -XPURGE http://example.com/resource/1234abcd/abc
更灵活的正则表达式清除使用禁令,将像这样发出:
curl -XPURGE -H"x-purge-regex: /resource/1234abcd/.*" http://example.com
禁令问题
禁止并非没有问题。
禁令的整个概念围绕着列表中与存储在缓存中的对象匹配的模式展开。
- 列表中的项目越多,处理所有项目所需的 CPU 周期就越多
- 缓存中的对象越多,处理所有对象所需的 CPU 周期就越多
因此,较大的禁令列表和大量的对象可能会造成大量的 CPU 开销
标签胜过 URL
禁令的另一个用例是基于标签的失效。
有时将实体更改转换为匹配的 URL 非常困难。有时您甚至不知道哪些 URL 受到实体更改的影响。
在这种情况下,标记内容并使与其中一个标记匹配的对象无效更有意义。
在您的应用程序中,您可以发出如下响应标头:
X-Cache-Tags: type:resource, id:1234abcd, category:product
如果您想要删除属于产品类别,您可以简单地发出以下禁令:
ban obj.http.x-cache-tags ~ category:product
基于标签的失效的更好解决方案
如果你打算使用禁令为了基于标签的失效,如果您的禁令列表增长得太快,并且缓存中需要验证的对象太多,您就会遇到相同的 CPU 问题。
更好的解决方案是使用xkey
,这是 Varnish 自带的模块Varnish 模块集合。 看https://github.com/varnish/varnish-modules/blob/master/src/vmod_xkey.vcc了解更多信息。
你必须编译这个模块,但是 API 更加灵活,而且性能也好很多。