Обзор конфигурации Varnish


Существует множество статей о том, как можно настроить Varnish. Спешу сообщить, что единого подхода к настройке не существует. Чем больше опций Вы укажете в файле конфигурации, тем больше может появиться непредвиденных обстоятельств.

В этой статье хочу провести обзор языка VCL, который используется при настройке Varnish и рассмотреть варианты настройки. Спешу обратить Ваше внимание на то, что Varnish не поддерживает SSL.

Итак, конфигурация Varnish описывается в двух файлах:

  • /etc/default/varnish для Debian/Ubuntu (/etc/sysconfig/varnish для RedHat/CentOS)
  • /etc/varnish/default.vcl

Первый содержит описание конфигурации демона Varnish. Можно установить следующие параметры:

START=yes
INSTANCE=$(uname -n)

Ключевой секцией в нем является раздел DAEMON_OPTS:

DAEMON_OPTS="-a публичный_ip_адрес:порт \
              -f путь_к_файлу_vcl \
              -T ip_адрес_для_админки:порт_для_админки \
              -t значение_ttl \
              -w минимальное_количество_процессов_varnish,максимальное_количество_процессов_varnish,время_жизни_процесса \
              -s хранилище_кэша"

Ниже приведен пример секции DAEMON_OPTS. В данном случае Varnish будет работать с файлом /etc/varnish/default.vcl. Кэш объектов будет храниться в файле размером 1Gb, расположенном на диске /var/lib/varnish/$(uname -n)/varnish_storage.bin:

DAEMON_OPTS="-a :80 \
             -T localhost:6082 \
             -t 120 \
             -w 10,30,50\
             -f /etc/varnish/default.vcl \
             -S /etc/varnish/secret \
             -s file,/var/lib/varnish/$INSTANCE/varnish_storage.bin,1G"

Ниже приведен пример секции DAEMON_OPTS. В данном случае Varnish будет работать с файлом /etc/varnish/website.vcl. Кэш объектов будет храниться в оперативной памяти (malloc) и под него будет отводиться 256Mb.

DAEMON_OPTS="-a :80 \
             -T localhost:6082 \
             -t 120\
             -w 10,30,50\
             -f /etc/varnish/website.vcl \
             -S /etc/varnish/secret \
             -s malloc,256m"

Возвращаюсь к утверждению о том, что единого подхода к настройке не существует, хочу заметить, что в зависимости от того кэшируете ли Вы статику (картинки, css файлы и js скрипты) нужно указывать разное хранилище для кэша.

В моей практике были сайты, у которых страницы имели много статических объектов в виде картинок, что существенно увеличивало время отгрузки страниц. Картинки редко менялись. В этом случае можно хранить кэш в файле на локальном диске и кэшировать страницы целиком, включая статические объекты. Скорость отгрузки страниц существенно увеличивалась при таком подходе (3-5 раз).

Этот блог крутится на слабом сервере, страницы легкие и не требуют много ресурсов для отдачи. Varnish настроен таким образом, что бы запросы статики отправлять прямиком на Nginx, а остальное кешировать/выдавать с кэша. В данном случае объекты хранятся в оперативной памяти с лимитом в 256 MB. Этого вполне достаточно.

Рассмотрим файл с расширением vcl в папке /etc/varnish и задается ключом "-f" в секции DAEMON_OPTS. Начинается он с описания так называемых бэк-эндов. В этом случае backend - тот самый Apache или NginX, на котором вертится сайт. Выглядит эта секция вот так:

backend default {
    .host = "127.0.0.1";
    .port = "8080";
}

Можно добавить проверку жизнеспособности:

backend default {
    .host = "127.0.0.1";
    .port = "8080";
    .probe = {
        .url = "/";
        .timeout = 0.3 s;
        .window = 8;
        .threshold = 3;
        .initial = 3;
      }
}

Если у Вас несколько серверов и Вы используете Varnish еще и в роли балансировщика нагрузки, тогда можно объявить несколько бэк-эндов и объединить их в директор:

backend www1 { .host = "192.168.0.10"; .port = "80";}
backend www2 { .host = "192.168.0.20"; .port = "80";}
backend www3 { .host = "192.168.0.30"; .port = "80";}
backend static { .host = "192.168.0.45"; .port = "80";}

director www round-robin {
  { .backend = www1; }
  { .backend = www2; }
  { .backend = www3; }
}

Дальше идет описание так называемых "подпрограмм" или "Subroutines", которые применяются ко всем запросам, проходящим через Varnish.

Стандартные подпрограммы:

  • vcl_recv
  • vcl_pipe
  • vcl_pass
  • vcl_hash
  • vcl_hit
  • vcl_miss
  • vcl_fetch
  • vcl_deliver
  • vcl_error

Общую последовательность работы Varnish можно описать с помощью следующей диаграммы:
Screenshot from 2014-07-17 10:33:48

1. vcl_recv отвечает за первоначальную обработку запроса. Дальнейшая судьба обработки запроса определяется именно здесь с помощью функции return(). Можно решить дальнейшую судьба запроса с помощью:

  • pass - отправить запрос в vcl_pass.
  • pipe отправить запрос в vcl_pipe.
  • lookup - искать запрошенный объект в хранилище кэша

Для того что бы отключить использование кэша для всех запросов кроме типа GET, добавьте следующие строки в эту секцию:

    if (req.request != "GET") { return (pass); }

Для того что бы отключить использование кэша для форм авторизации (Basic auth), добавьте следующие строки в эту секцию:

    if (req.http.Authorization || req.request == "POST") 
    {
        return (pass);
    }

Следующая конструкция отключит использование кэша для админки блога WordPress. Соответственно wp-admin можно поменять на нужное Вам значение:

    if (req.url == "^/wp-admin") {
        return (pass);
    }

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

    if (req.url ~ "^/(wp-content|media|images|ваш_вариант/.*\.(css|js|ico|gif|jpeg|jpg|png|eot|ttf|swf|woff)$") {
   unset req.http.Cookie;
   return (pass);
    }

Аналогично можно отправить все запросы статических файлов на отдельный бэк-энд,если он у Вас предусмотрен для этих целей:

    if (req.url ~ "^/(wp-content|media|images|ваш_вариант/.*\.(css|js|ico|gif|jpeg|jpg|png|eot|ttf|swf|woff)$") {
       unset req.http.Cookie;
       set req.backend = static;
    }

Можно использовать конкретный бэкэнд в зависимости от значения HOST в заголовках запроса. Допустим у Вас есть dev версия сайта и лежит она на одном из описанных бэк-эндов (допустим www2):

    if (req.http.host ~ "dev.website.com") {set req.backend = www2 ;}
    else if (req.http.host ~ "www.website.com") {set req.backend = www; }

Полезной может быть нормализация кодирования:

    if (req.http.Accept-Encoding) {
        if (req.http.Accept-Encoding ~ "gzip") {
            set req.http.Accept-Encoding = "gzip";
        }
        elsif (req.http.Accept-Encoding ~ "deflate") {
            set req.http.Accept-Encoding = "deflate";
        }
        else {
            remove req.http.Accept-Encoding;
        }
    }

Закрывается секция функцией return (), с аргументом pass, pipe или lookup.

Пример секции

sub vcl_recv {
    if (req.request != "GET") { return (pass); }
    if (req.url == "^/wp-admin") {
        return (pass);
    }

    if (req.url ~ "^/(wp-content|media|images|ваш_вариант/.*\.(css|js|ico|gif|jpeg|jpg|png|eot|ttf|swf|woff)$") {
       unset req.http.Cookie;
       set req.backend = static;
    }

    if (req.http.Accept-Encoding) {
        if (req.http.Accept-Encoding ~ "gzip") {
            set req.http.Accept-Encoding = "gzip";
        }
        elsif (req.http.Accept-Encoding ~ "deflate") {
            set req.http.Accept-Encoding = "deflate";
        }
        else {
            remove req.http.Accept-Encoding;
        }
    }

    return (lookup);

 }

2. При попадании запроса в vcl_pass он доставляется на прямую бэк-энду, минуя кэш.

3. При попадании запроса в vcl_pipe происходит своеобразное замыкание клиента на бэк-энд. Varnish курит в сторонке или обрабатывает другие запросы. Если честно большой разницы между vcl_pass и vcl_pipe я не вижу.

4. vcl_hash отвечает за создание хэш-слепка объекта в хранилище кэша. Дополнительных опций не имеет.

5. vcl_miss срабатывает, если запрашиваемый объект не был найден в хранилище кэша. По умолчанию отправляет объект на обработку vcl_fetch.

6. vcl_hit срабатывает, если запрашиваемый объект был найден в хранилище кэша. По умолчанию отправляет объект на обработку vcl_deliver.

7. vcl_fetch срабатывает, когда запрашиваемый объект был получен от бэк-энда.

Если для Вас критично, что бы в логи бэк-энд серверов попадали реальные значения ip адресов посетителей, добавьте следующие строки в эту секцию:

    remove req.http.X-Forwarded-For; 
    set req.http.X-Forwarded-For = client.ip;

Для того, что бы задать время жизни объекта в хранилище кэша, нужно сначала убрать заголовок, обозначающий время жизни объекта:

    unset beresp.http.expires;

А потом указать время жизни объекта в хранилище (в секундах):

    set beresp.ttl = 86400 s;

В конце секции:

return (deliver);
Пример секции

sub vcl_fetch {
    remove req.http.X-Forwarded-For;
    set req.http.X-Forwarded-For = client.ip;
    set beresp.ttl = 86400 s;
     return (deliver);
 }

8. vcl_deliver срабатывает перед доставкой объекта с хранилища кэша клиенту. Здесь можно либо добавить, либо убрать нужные заголовки (headers) в http ответе:

    remove resp.http.X-Varnish;
    remove resp.http.Via;
    remove resp.http.Age;
    remove resp.http.X-Purge-URL;
    remove resp.http.X-Purge-Host;
    remove resp.http.X-CF-Powered-By;

    set resp.http.X-Custom-name custom-value 
Пример секции

sub vcl_deliver {
    remove resp.http.X-Varnish;
    remove resp.http.Via;
    remove resp.http.Age;
    remove resp.http.X-Purge-URL;
    remove resp.http.X-Purge-Host;
    remove resp.http.X-CF-Powered-By;

    return (deliver);
}

Так же обратите внимание на статью "Очистка кэша Varnish" и Размышления о кластеризации: Часть 3 — Varnish кэш

Share Button
(Visited 1 228 times, 1 visits today)

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *