У меня есть приложение 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. Если вы не устанавливаете этот предел, вам следует следить за глобальной очередью пассажиров (при условии, что вы используете пассажира).