Varnish 配置仅为未登录用户缓存

Varnish 配置仅为未登录用户缓存

我有一个 Ruby on Rails 应用程序,前端是 varnish+nginx。由于除非您是登录用户,否则大多数网站内容都是静态的,因此我想在用户注销时使用 varnish 大量缓存网站,但在用户登录时仅缓存静态资产。

当用户登录时,他们的 Cookie:标头中会出现 cookie“user_credentials”,此外,我需要跳过 /login 和 /sessions 上的缓存,以便用户可以首先获取他们的“user_credentials”cookie。

Rails 默认不设置缓存友好的 Cache-control 标头,但是我的应用程序在用户未登录时设置“public,s-max-age=60”标头。Nginx 设置为返回所有静态资产的“远期”过期标头。

我目前的配置是登录时完全绕过所有内容的缓存,包括静态资产 — — 并在退出时返回所有内容的缓存 MISS。我花了几个小时绕来绕去,这是我当前的 default.vcl

    director rails_director round-robin {
  { 
    .backend = { 
      .host = "xxx.xxx.xxx.xxx"; 
      .port = "http";
      .probe = {
        .url = "/lbcheck/lbuptest";
        .timeout = 0.3 s;
        .window = 8;
        .threshold = 3;
      }
    } 
  }
}

sub vcl_recv {

  if (req.url ~ "^/login") {
    pipe;
  }

  if (req.url ~ "^/sessions") {
    pipe;
  }
  # The regex used here matches the standard rails cache buster urls
  # e.g. /images/an-image.png?1234567
  if (req.url ~ "\.(css|js|jpg|jpeg|gif|ico|png)\??\d*$") {
    unset req.http.cookie;
    lookup;
  } else {
    if (req.http.cookie ~ "user_credentials") {
      pipe;
    }
  }

  # Only cache GET and HEAD requests
  if (req.request != "GET" && req.request != "HEAD") {
    pipe;
  }

}

sub vcl_fetch {

  if (req.url ~ "^/login") {
    pass;
  }

  if (req.url ~ "^/sessions") {
    pass;
  }

  if (req.http.cookie ~ "user_credentials") {
    pass;
  } else {
    unset req.http.Set-Cookie;
  }

  # cache CSS and JS files
  if (req.url ~ "\.(css|js|jpg|jpeg|gif|ico|png)\??\d*$") {
    unset req.http.Set-Cookie;
  } 

  if (obj.status >=400 && obj.status <500) {
    error 404 "File not found";
  }

  if (obj.status >=500 && obj.status <600) {
    error 503 "File is Temporarily Unavailable";
  }

}

sub vcl_deliver {
  if (obj.hits > 0) {
          set resp.http.X-Cache = "HIT";
  } else {
          set resp.http.X-Cache = "MISS";
  }
}

答案1

好的,最后我设法使用以下 vcl 文件解决了这个问题。请注意,我添加了一些额外的位,以便在后端死机时允许缓存过期宽限。

看来我的主要失败是unset req.http.Set-Cookie;在应该使用unset obj.http.Set-Cookie;vcl_fetch部分时使用了它。(obj在 vcl_fetch 和reqvcl_recv 部分)。

director rails_director round-robin {
  { 
    .backend = { 
      .host = "xxx.xxx.xxx.xxx"; 
      .port = "http";
      .probe = {
        .url = "/lbcheck/lbuptest";
        .timeout = 0.3 s;
        .window = 8;
        .threshold = 3;
      }
    } 
  }
}

sub vcl_recv {

  if (req.backend.healthy) {
    set req.grace = 30s;
  } else {
    set req.grace = 1h;
  }

  if (req.url ~ "^/login") {
    pipe;
  }

  if (req.url ~ "^/sessions") {
    pipe;
  }

  if (req.url ~ "\.(css|js|jpg|jpeg|gif|ico|png)\??\d*$") {
    unset req.http.cookie;
    lookup;
  } else {
    if (req.http.cookie ~ "user_credentials") {
      pipe;
    } else {
      unset req.http.cookie;
    }
  }

  # Only cache GET and HEAD requests
  if (req.request != "GET" && req.request != "HEAD") {
    pipe;
  }

}

sub vcl_fetch {

  set obj.grace = 1h;

  if (req.url ~ "^/login") {
    pass;
  }

  if (req.url ~ "^/sessions") {
    pass;
  }

  if (req.http.cookie ~ "user_credentials") {
    pass;
  } else {
    unset obj.http.Set-Cookie;
  }

  # cache CSS and JS files
  if (req.url ~ "\.(css|js|jpg|jpeg|gif|ico|png)\??\d*$") {
    unset obj.http.Set-Cookie;
  } 

  if (obj.status >=400 && obj.status <500) {
    error 404 "File not found";
  }

  if (obj.status >=500 && obj.status <600) {
    error 503 "File is Temporarily Unavailable";
  }

}

sub vcl_deliver {
  if (obj.hits > 0) {
          set resp.http.X-Cache = "HIT";
  } else {
          set resp.http.X-Cache = "MISS";
  }
}

答案2

我无法发表评论因此我将其作为答案发布。

注意:从 2.1.0 开始,obj.* 在 vcl_fetch 中被称为 beresp.*,并且 obj.* 现在是只读的。

这些似乎也最好放在 vcl_recv 而不是 vcl_fetch 中:

  if (req.url ~ "^/login") {
    pipe;
  }

  if (req.url ~ "^/sessions") {
    pipe;
  }

最后,在你的后端定义中,我会添加

.max_connections = 32;

调整您允许 nginx/apache 创建的 Passenger 后端数量。如果您不设置此限制,则应密切关注 Passenger 全局队列(假设您正在使用 Passenger)。

相关内容