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

повторяющиеся страницы кеша: Varnish

Недавно мы настроили 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:

В качестве альтернативы вы можете удалить все вышеупомянутые строки. Конечный результат такой же.