24

最近我向 Rails 应用程序堆栈添加了一个 Varnish 实例。可以通过使用 Cache-Control Header 缓存某个资源来说服其默认配置中的清漆,如下所示:

Cache-Control: max-age=86400, public=true

我使用控制器中的 expires_in 语句实现了这一点:

def index
  expires_in 24.hours, public: true
  respond_with 'some content'
end

效果很好。我没想到的是,Cache-Control 标头也会影响浏览器。这导致了一个问题 - Varnish 和我的用户浏览器都缓存了某个资源。资源已从清漆中正确清除,但浏览器不会尝试再次请求它,除非达到 max-age。

所以我想知道我是否应该将'expires_in'与Varnish结合使用?我可以在 Varnish 前过滤 Nginx 或 Apache 实例中的 Cache-Control 标头,但这似乎很奇怪。

任何人都可以启发我吗?

问候菲利克斯

4

1 回答 1

15

这实际上是一个非常好的和有效的问题,也是一个非常常见的反向代理问题。

问题是只有一个 Cache-Control 属性,它适用于客户端浏览器(私有缓存)和/或代理服务器(共享缓存)。如果您根本不希望 3rd 方代理缓存您的内容,并且希望您的 Varnish(或 Rails 后端)处理每个请求,则必须从 Varnish 发送适当的 Cache-Control 标头。

修改后端发送的 Cache-Control 标头在https://www.varnish-cache.org/trac/wiki/VCLExampleLongerCaching有详细讨论

你可以从两个不同的角度来解决这个问题。如果你想在 Rails 后端定义 max-age,例如为不同的对象指定不同的 TTL,你可以使用上面链接中描述的方法。

另一种解决方案是根本不从后端发送 Cache-Control 标头,而是在 varnish vcl_fetch() 中为对象定义所需的 TTL。这是我们采取的方法。

我们在 Varnish 中有一个 600 秒的默认 TTL,并为在进行更改时明确清除的页面定义更长的 TTL。这是我们当前的 vcl_fetch() 定义:

sub vcl_fetch {
  if (req.http.Host ~ "(forum|discus)") {
    # Forum pages are purged explicitly, so cache them for 48h
    set beresp.ttl = 48h;
  }

  if (req.url ~ "^/software/") {
    # Software pages are purged explicitly, so cache them for 48h
    set beresp.ttl = 48h;
  }

  if (req.url ~ "^/search/forum_search_results" ) {
    # We don't want forum search results to be cached for longer than 5 minutes
    set beresp.ttl = 300s;
  }

  if(req.url == "/robots.txt") {
    # Robots.txt is updated rarely and should be cached for 4 days
    # Purge manually as required
    set beresp.ttl = 96h;
  }

  if(beresp.status == 404) {
    # Cache 404 responses for 15 seconds
    set beresp.http.Cache-Control = "max-age=15";
    set beresp.ttl = 15s;
    set beresp.grace = 15s;
  }
}

在我们的例子中,我们根本不从 Web 后端服务器发送 Cache-Control 标头。

于 2012-04-27T07:59:36.863 回答