Varnish Cache广泛用于缓存Web内容,以最大化Web性能并减少原始服务器负载。 在我们的核心,我们一直在关注Web缓存,以支持性能,可伸缩性,稳定性以及这些属性所带来的所有固有好处-从更好的用户体验到节省底线。 但是有时我们仍然必须重提缓存的重要性。 有时这意味着要解释如何使用Varnish Cache并摆脱所有使它成为独特的“救生”(至少对于网站和应用程序而言)和炫酷技术的风吹草动。
Varnish Cache的本质“怪异”
Varnish Cache是具有HTTP后端的HTTP服务器,可以为文件提供服务。 它具有线程架构,但没有事件循环。 因为写代码可以使用阻塞的系统调用,所以它比必须处理事件循环的Apache或NGINX更容易使用。
Varnish Cache有一种怪异的记录到共享内存而不是磁盘的方式。 之所以这样设计,是因为每秒将10,000个HTTP事务记录到旋转的硬盘中非常昂贵。
Varnish将所有内容(每个请求大约200行)记录到内存中。 如果没有人正在寻找该信息,它将被覆盖。 Varnish是唯一执行此操作的应用程序。
灵活性:帮助自己适应一些VCL
Varnish Cache的最大区别在于其配置语言。 Varnish配置语言 (VCL)创建于10年前,以支持Varnish Cache 1.0。 与Apache或其他程序不同,Varnish Cache没有传统的配置。 相反,它具有以这种特定语言编写的一组策略。 这些策略被编译成本机(二进制)代码,并且本机代码被加载然后运行。
Varnish Cache架构师Poul-Henning Kamp说,VCL是作为一个盒子而构建的,它具有一组可以根据需要使用的工具,而不是固定在盒子中的固定产品。 如今,VCL有100个易于使用的模块。 实际上,我们的Varnish峰会始终包含一个讲习班,教人们编写模块。
我们一次又一次地听到VCL是人们喜欢甚至发展成为对Varnish Cache进行严格保护的重要原因之一。 它的灵活性打开了几乎可以做任何人想要做的事情的门,将传统的程序约束排除在了窗外。
那么,VCL工具箱中主要的工具是什么?如何最好地使用它们?
吹扫
Varnish不支持立即清除内容。 您不仅可以立即下载,安装和清除,还需要一些组装。 除了使用默认配置交付此代码外,Varnish Cache要求其用户在指甲下沾上一些污垢。 但是,设置清除的配置很简单,您可以从中获得所需的确切信息。
sub vcl_recv {
if (req.method == "PURGE") {
return (purge); } }
如果您不希望Internet上的任何人清除您的缓存中的内容,我们将设置ACL限制访问权限以清除此特定事件:
acl purge {
"localhost";
"192.168.55.0"/24;
}
sub vcl_recv {
if (req.method == "PURGE") {
if (!client.ip ~ purge) {
return(synth(405,"Not allowed."));
}
return (purge); } }
在Varnish Cache中添加“功能”:限制热链接
Varnish框架允许每个用户实现自己所需的功能。 第一个贡献的功能是使用VCL限制热链接。 热链接是在窃取其他人在网络上的资源,在上面写一个简短的帖子,然后使用他们的图像来说明您的观点,以便最终他们要支付带宽费用。
当热链接非法使用其资源时,Varnish允许服务器阻止此过程。 例如,Varnish可以通过利用VMOD(Varnish模块)( vsthrottle ) 来增加节流来限制每分钟发生的次数。
用户只需导入并加载节流模块。 下面的VCL代码段显示了一种限制热链接的方法。 在此示例中,我们应用了三个规则。 第一条规则检查请求的URL是否以“ / assets /”开头。 第二和第三条规则可以保护您的资产免于热链接。 这是通过检查引荐来源网址是否超出您的期望以及其他域在60秒内是否已多次请求您的资产来完成的。 这就是油门功能。 该URL用作限制的密钥。 许可证等于每60秒10次。 允许我们在没有此URL作为其引用的资产下提供URL,并且如果该URL命中,我们将抛出错误403,并禁止热链接。 限制也可以扩展为改为使用内存缓存,以便用户在其群集中获得中央帐户。
import vsthrottle;
(..)
if (req.url ~
"^/assets/" &&
(req.http.referer !~
"^http://www.example.com/") &&
vsthrottle.is_denied(req.url, 10, 60s) {
return(error(403,"Hotlinking prohibited");
}
处理Cookie
Varnish不会缓存Cookie所请求的内容。 如果请求具有关联的cookie,它也不会传递缓存命中。 而是使用VMOD剥离cookie。 真正的男人和女人将使用正则表达式过滤掉Cookie。 对于我们其他人,Varnish提供了一个如下所示的cookie模块:
import cookie;
sub vcl_recv {
cookie.parse ("cookie1: value1; cookie2: value2");
cookie.filter_except("cookie1");
// get_string() will now yield
// "cookie1: cookie2: value2;"; }
Varnish也不喜欢设置Cookie标头。 如果看到后端正在发送设置的Cookie标头,则不会缓存该对象。 解决方案是删除设置的Cookie标头或修复后端。
- Set-Cookie标头可停用Cookie。
- 解决方案:删除Set-Cookie或固定后端。
宽限模式:阻止雷声浪涌
如果没有新内容,宽限模式允许Varnish提供过时的内容。 它通过异步刷新后端的内容来提高性能。
当最初将Varnish 1.0用作挪威小报报纸Verdens Gang的在线分支的缓存解决方案时,存在大量的线程堆积问题。 报纸首页的发送速度为3,000次/秒,但是其内容管理系统(CMS)速度很慢,并且花了三秒钟来重新生成首页。
在某些站点上,如果您遵循RFC,则代理缓存将使该首页无效或超时。 然后,用户来了,需要获取首页的新版本。 Varnish通过缓存合并来做到这一点。 随着新用户的到来,他们被放置在等待列表中。 (其他缓存会将用户发送到后端,这会杀死后端。)
如果每秒将另外3,000个用户添加到等待列表中,则三秒钟后,则有9,000个用户正在等待后端交付内容。 最初,Varnish会采用这些内容,与其9,000个线程进行对话,然后尝试一次将其全部推出。 我们称这种情况为雷电群,它立即杀死了服务器。
为了解决此问题,Varnish决定只使用旧的首页,而不是等待服务器重新生成内容。 除非您提供实时财务信息,否则没人会在乎内容是否过时20秒。
多年来,Grace的语义已略有变化。 在Varnish 4.0(如果启用)中,它看起来像这样:
sub vcl_backend_response {
set beresp.grace = 2m;
}
宽限期设置在后端响应对象上。 如果设置为两分钟,则Varnish会将对象保留在其TPL之后两分钟。 如果在那个时间要求,它将优先提供缓存中的内容而不是缓存中的内容。 它将使用对象,然后异步刷新对象。
打开引擎盖
Varnish Cache不需要用户阅读源代码,而是提供了一个默认的VCL,他们可以在其中尝试尽可能多地添加语义。 使用Grace之类的功能,用户可以阅读VCL并查看其功能。
Insert code
sub vcl_hit {
if (obj.ttl >= 0s) {
// A pure unadulterated hit, deliver it
return (deliver);
}
if (obj.ttl + obj.grace > 0s) {
// Object is in grace, deliver it
// Automatically triggers a background fetch
return (deliver);
}
// fetch & deliver once we get the result
return (fetch);
}
如果对象VCL大于零秒,则它具有正TTL。 退货并交付。 服务。
如果TTL和Grace大于零秒,则它位于Grace中,Varnish会提供它。
如果TTL和Grace小于零秒,我们将阻止并获取它。
修改Grace语义
那些正在使用金融工具进行扩展并且不愿意提供过时服务的组织可能想要修改Grace语义。 此处的第一位保持不变。 如果后端运行状况不佳,并且TTL和Grace超过零秒会交付,则重写第二部分。
sub vcl_hit { if (obj.ttl >= 0s) {
// A pure unadulterated hit, deliver it
return (deliver);
}
if (!std.healthy(req.backend_hint) &&
(obj.ttl + obj.grace > 0s)) {
return (deliver);
}
// fetch & deliver once we get the result
return (fetch);
}
您可能想知道的几件事:
- beresp是后端请求对象。
- req是请求对象。 在vcl_recv中使用。
- bereq是后端请求对象。 在vcl_backed_fetch中使用。
- beresp是后端响应。 在vcl_backend_response中使用。
- resp是响应对象。 在vcl_deliver中使用。
- obj是内存中的原始对象。 在vcl_hit中使用。
- man(7)vcl了解更多信息。
状态机

每个请求都经过状态。 在每次使用时都会运行自定义代码以修改请求对象。 运行特定于用户的代码后,Varnish将确定是命中还是未命中,然后运行VCL命中或VCL未命中。 如果很成功,VCL就会交付。 错过了后端获取。 90%的用户特定更改在此处发生。
在Linux上进行调优的快速指南
Linux中的可调参数设置非常保守。 我们最讨厌的两个是SOMAXCONN和TCP_MAX_SYN_Backlog 。
当我们收听套接字时,Varnish将花费几秒钟来收听呼叫。 如果这些线程变得繁忙,内核将开始排队。 该队列不允许超出SOMAXCONN。 Varnish会在侦听深度队列中请求1024个连接,但是内核会覆盖它,您得到928个。由于Varnish以root特权运行,因此它应该能够确定自己的侦听深度,但是Linux最了解。
如果用户想降低超出监听深度时拒绝连接的风险,则可能希望增加该限制。 他们必须决定是否最好失败,然后将错误页面交付给用户。
TCP_MAX_SYN_Backlog定义在内核假设其受到攻击之前,三次握手中可以有多少个未完成的连接。 默认值为128。但是,如果闪存在Internet上形成并进入您的站点,则每秒可能会有128个以上的新TCP连接。
不要搞混tcp_tw_recycle 。 谷歌搜索这些东西时要小心。 有很多与之相关的恶魔。
Linux中的工作空间
在Varnish中,每个线程中都有本地内存。 因为回滚很昂贵,所以我们不需要每次都需要一点内存时就回滚。 相反,如果用户有大量的VCL来回操作字符串,这将耗尽所有工作空间,则我们会为每个线程预先分配内存。
Varnish不进行连接跟踪。 合同模块非常缓慢。 默认值是使用五个线程运行。 启动新线程相对较快,但是如果计划每秒执行1,000个连接= 1,000个线程,则您具有用于预分配线程的参数。
回顾一下:
- 注意工作区。
- 不要进行连接跟踪。
- 将线程提高到每个线程一请求/秒。
清漆缓存的怪异平衡
Varnish Cache强大的灵活性和优势并没有预先包装在方盒中(这可能有些奇怪),因此,它可能不是每个人都合适的解决方案。 但是,在寻找自定义和控制Web性能和可伸缩性的方法时,它的灵活性可能会改变游戏规则。
翻译自: https://opensource.com/business/16/2/getting-started-with-varnish-cache