Varnish Cache 网络应用加速器入门

暂无读者喜欢这篇文章。
Getting started with web app accelerator Varnish Cache

Per Buer。CC BY-SA 4.0。

Varnish Cache 被广泛用于缓存网络内容,以最大限度地提高网络性能并降低源服务器负载。我们的核心一直是关于网络缓存,以支持性能、可扩展性、稳定性以及与这些属性相关的内在优势——从更好的用户体验到最终的成本节省。但有时我们仍然需要强调缓存的重要性。有时这意味着解释如何使用 Varnish Cache 并充分利用使其成为独特、“救命”(至少对于网站和应用程序而言)和酷炫技术的所有优势。

Varnish Cache 的本质“怪异”之处

Varnish Cache 是一种具有 HTTP 后端的 HTTP 服务器,可以提供文件服务。它具有线程架构,但没有事件循环。由于写入代码可以使用阻塞系统调用,因此它比 ApacheNGINX 更易于使用,在 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 秒内请求您的资产超过 10 次来完成的。这就是限制功能。URL 用作限制的键。permit 等于每 60 秒 10 次。我们被允许为不以此作为引用的资产下的 URL 提供服务,如果命中,我们只需抛出 错误 403,并禁止盗链。限制也可以扩展为使用 memcache,以便用户在其集群中获得中央记帐。

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 也不喜欢 set-cookie 标头。如果它看到后端正在发送 set-cookie 标头,它将不会缓存该对象。解决方案是删除 set-cookie 标头或修复后端。

  • Set-Cookie 标头会禁用 Cookie。
  • 解决方案:删除 Set-Cookie 或修复后端。

Grace 模式:防止惊群效应

Grace 模式允许 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;
}

Grace 在后端响应对象上设置。如果设置为两分钟,Varnish 会将对象保留在其 TTL 过期后两分钟。如果在该时间内请求它,它将优先提供缓存中的内容,而不是缓存外的。它将使用该对象,然后异步刷新该对象。

打开引擎盖

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 Cache flowchart

每个请求都经过状态。自定义代码在每次使用时运行,以修改请求对象。在用户特定代码运行后,Varnish 将决定它是命中还是未命中,然后运行 VCL hit 或 VCL miss。如果是命中,VCL 交付。未命中会转到后端获取。90% 的用户特定更改发生在此处。

Linux 调优快速指南

Linux 中的可调参数设置非常保守。我们发现最烦人的两个是 SOMAXCONNTCP_MAX_SYN_Backlog

当我们监听套接字时,Varnish 需要几秒钟才能监听调用。如果这些线程变得繁忙,内核将开始排队。该队列不允许增长超过 SOMAXCONN。Varnish 将在监听深度队列中请求 1024 个连接,但内核会覆盖它,您将获得 928 个连接。由于 Varnish 以 root 权限运行,它应该能够决定自己的监听深度,但 Linux 自认为更了解。

如果用户希望降低在监听深度不足时拒绝连接的风险,他们可能希望增加该限制。他们必须决定,向用户交付错误页面是否更好。

TCP_MAX_SYN_Backlog 定义了在内核假定它受到攻击之前,三次握手中可以有多少个未完成的连接。默认值为 128。但是,如果 Internet 上形成快闪暴民并访问您的站点,您每秒可能会有超过 128 个新的 TCP 连接。

不要乱用 tcp_tw_recycle。在 Google 上搜索这些内容时要小心。有很多与它们相关的恶魔。

Linux 中的工作区

在 Varnish 中,本地内存位于每个线程中。由于回滚成本很高,因此我们不会在每次需要少量内存时都回滚。相反,如果用户有大量 VCL 来回操作字符串,这将耗尽所有工作区,我们会为每个线程预先分配内存。

Varnish 不进行连接跟踪;contract 模块速度非常慢。默认情况下以五个线程运行。启动新线程相对较快,但如果计划每秒执行 1,000 个连接 = 1,000 个线程,那么您就有了预分配线程的参数。

总结

  • 注意工作区。
  • 不要进行连接跟踪。
  • 将线程数增加到每个线程每秒一个请求。

Varnish Cache 的怪异-酷炫平衡

Varnish Cache 强大的灵活性和优势并非预先包装在一个方盒子中(这可能会让一些人觉得很奇怪),因此它可能不是适合所有人的解决方案。然而,当寻找自定义和控制网络性能和可扩展性的方法时,它的灵活性可能会改变游戏规则。

User profile image.
Per Buer 是 Varnish Software 的 CTO 和创始人,Varnish Software 是开源项目 Varnish Cache 的幕后公司。Buer 曾是一名程序员,后来成为系统管理员,然后是经理,最后成为企业家。跑步、越野滑雪,并努力阻止他的两个儿子拆毁房子。

评论已关闭。

© . All rights reserved.