Назад | Перейти на главную страницу

Конфигурация Varnish для кеширования только для незарегистрированных пользователей

У меня есть приложение Ruby on Rails, запущенное varnish + nginx. Поскольку большая часть содержимого сайтов статична, если вы не вошли в систему, я хочу сильно кэшировать сайт с помощью varnish, когда пользователь выходит из системы, но только для кеширования статических активов, когда они вошли в систему.

Когда пользователь вошел в систему, в его заголовке Cookie: будет присутствовать файл cookie user_credentials, кроме того, мне нужно пропустить кеширование в / login и / sessions, чтобы пользователь мог получить свой cookie user_credentials в первую очередь .

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";
  }
}

Хорошо, в конце концов мне удалось решить эту проблему с помощью следующего файла vcl. Обратите внимание, что я добавил пару дополнительных битов, чтобы разрешить отсрочку истечения срока действия кеша при отказе серверной части.

Кажется, моя главная неудача заключалась в использовании unset req.http.Set-Cookie; когда я должен был использовать unset obj.http.Set-Cookie; в vcl_fetch раздел. (obj в vcl_fetch и req в разделе vcl_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.1.0, obj. * Называется beresp. * В vcl_fetch, а obj. * Теперь доступен только для чтения.

Также кажется, что их лучше разместить в vcl_recv вместо vcl_fetch:

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

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

Наконец, в вашем определении бэкенда я бы добавил

.max_connections = 32;

Отрегулируйте количество бэкэндов для пассажиров, которое вы разрешили создавать nginx / apache. Если вы не устанавливаете этот предел, вам следует следить за глобальной очередью пассажиров (при условии, что вы используете пассажира).