Недавно мы настроили Varnish на нашем сервере, он был успешно настроен, но мы заметили, что если мы открываем любую страницу в нескольких браузерах, Varnish отправляет запрос на Apache, независимо от того, кэширована страница или нет. Если мы дважды обновим страницу в каждом браузере, это создаст дубликаты одной и той же страницы.
Что именно должно произойти:
Если какая-либо страница кэшируется Varnish, последующий запрос должен обслуживаться самим Varnish, когда мы открываем ту же страницу в браузере ИЛИ открываем эту страницу с другого IP-адреса.
Ниже приведен мой файл default.vcl.
backend default {
.host = "127.0.0.1";
.port = "80";
}
sub vcl_recv {
if( req.url ~ "^/search/.*$")
{
}else {
set req.url = regsub(req.url, "\?.*", "");
}
if (req.restarts == 0) {
if (req.http.x-forwarded-for) {
set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip;
} else {
set req.http.X-Forwarded-For = client.ip;
}
}
if (!req.backend.healthy) {
unset req.http.Cookie;
}
set req.grace = 6h;
if (req.url ~ "^/status\.php$" ||
req.url ~ "^/update\.php$" ||
req.url ~ "^/admin$" ||
req.url ~ "^/admin/.*$" ||
req.url ~ "^/flag/.*$" ||
req.url ~ "^.*/ajax/.*$" ||
req.url ~ "^.*/ahah/.*$") {
return (pass);
}
if (req.url ~ "(?i)\.(pdf|asc|dat|txt|doc|xls|ppt|tgz|csv|png|gif|jpeg|jpg|ico|swf|css|js)(\?.*)?$") {
unset req.http.Cookie;
}
if (req.http.Cookie) {
set req.http.Cookie = ";" + req.http.Cookie;
set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";");
set req.http.Cookie = regsuball(req.http.Cookie, ";(SESS[a-z0-9]+|SSESS[a-z0-9]+|NO_CACHE)=", "; \1=");
set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", "");
set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", "");
if (req.http.Cookie == "") {
unset req.http.Cookie;
}
else {
return (pass);
}
}
if (req.request != "GET" && req.request != "HEAD" &&
req.request != "PUT" && req.request != "POST" &&
req.request != "TRACE" && req.request != "OPTIONS" &&
req.request != "DELETE")
{return(pipe);} /* Non-RFC2616 or CONNECT which is weird. */
if (req.request != "GET" && req.request != "HEAD") {
return (pass);
}
if (req.http.Accept-Encoding) {
if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg)$") {
# No point in compressing these
remove req.http.Accept-Encoding;
} else if (req.http.Accept-Encoding ~ "gzip") {
set req.http.Accept-Encoding = "gzip";
} else if (req.http.Accept-Encoding ~ "deflate") {
set req.http.Accept-Encoding = "deflate";
} else {
# unknown algorithm
remove req.http.Accept-Encoding;
}
}
return (lookup);
}
sub vcl_deliver {
if (obj.hits > 0) {
set resp.http.X-Varnish-Cache = "HIT";
}
else {
set resp.http.X-Varnish-Cache = "MISS";
}
}
sub vcl_fetch {
if (beresp.status == 404 || beresp.status == 301 || beresp.status == 500) {
set beresp.ttl = 10m;
}
if (req.url ~ "(?i)\.(pdf|asc|dat|txt|doc|xls|ppt|tgz|csv|png|gif|jpeg|jpg|ico|swf|css|js)(\?.*)?$") {
unset beresp.http.set-cookie;
}
set beresp.grace = 6h;
}
sub vcl_hash {
hash_data(req.url);
if (req.http.host) {
hash_data(req.http.host);
} else {
hash_data(server.ip);
}
return (hash);
}
sub vcl_pipe {
set req.http.connection = "close";
}
sub vcl_hit {
if (req.request == "PURGE")
{ban_url(req.url);
error 200 "Purged";}
if (!obj.ttl > 0s)
{return(pass);}
}
sub vcl_miss {
if (req.request == "PURGE")
{error 200 "Not in cache";}
}
Решение
Ловушка - Варьируется: User-Agent
Некоторые приложения или серверы приложений отправляют Vary: User-Agent вместе со своим содержимым. Это указывает Varnish кэшировать отдельную копию для каждого варианта User-Agent. Их много. Даже один уровень исправлений одного и того же браузера будет генерировать не менее 10 различных заголовков User-Agent в зависимости от того, в какой операционной системе они работают.
Поэтому, если вам действительно нужно варьировать на основе User-Agent, обязательно нормализуйте заголовок, иначе ваша скорость попадания сильно пострадает. Используйте приведенный выше код в качестве шаблона.
https://www.varnish-cache.org/docs/3.0/tutorial/vary.html#tutorial-vary
Обходной путь
Один из обходных путей - это сделать то, что мы называем «промывкой агента-пользователя», когда Varnish переписывает Useragent для нескольких различных вариантов, которые действительно волнуют ваш бэкэнд, в следующих строках:
sub vcl_recv {
if (req.http.user-agent ~ "MSIE") {
set req.http.user-agent = "MSIE";
} else {
set req.http.user-agent = "Mozilla";
}
}
Во-первых, varnish не может кэшировать 2 копии URL.
Теперь я не уверен в проверке попаданий / промахов, но когда мне нужно будет проверить, я сделаю это в firefox и использую для этого Firebug.
Я открою firebug и открою сайт.
При этом он покажет возраст каждой полученной страницы / изображения, как показано на прилагаемом рисунке.
Если возраст со временем увеличивается, то мне хорошо подходит Varnish.
И что я вижу, он отлично работает и для вашего сайта.
Вот что помогло мне решить эту проблему:
Раскомментировать Закомментируйте или удалите строки, образующие ваш vch_hash
функцию и перезапустите лак. vcl_hash
используется для создания определенных кешей, скажем, для пользователя, сеанса или определенного IP-адреса. Если вы хотите, чтобы страница обслуживалась из (после кэширования) кеша, вы можете отказаться от функции vcl_hash.
На всякий случай сначала протестируйте его в тестовой среде.
HTH.
Изменить (пояснение)
Опция 1:
Закомментируйте эти строки, добавив знак «#» в начале каждой строки. Итак, эти строки
sub vcl_hash {
hash_data(req.url);
if (req.http.host) {
hash_data(req.http.host);
} else {
hash_data(server.ip);
}
return (hash);
}
станет:
#sub vcl_hash {
# hash_data(req.url);
# if (req.http.host) {
# hash_data(req.http.host);
# } else {
# hash_data(server.ip);
# }
# return (hash);
#}
Строки, начинающиеся с #
игнорируются лаком.
Вариант 2:
В качестве альтернативы вы можете удалить все вышеупомянутые строки. Конечный результат такой же.