Об­работ­ка боль­шого чис­ла зап­росов может быть весь­ма тяжелой задачей, забира­ющей ресур­сы веб‑сер­вера. Что­бы снять наг­рузку, исполь­зуют фрон­тенд, в качес­тве которо­го могут выс­тупать лег­кие nginx/lighttpd или кеширу­ющий прок­си‑сер­вер. Во вто­ром качес­тве очень популя­рен Squid, он уни­вер­сален, но не всег­да опти­мален. Но имен­но в этой задаче его более эффектив­но заменя­ет Varnish.
 

Немного о проекте

Varnish пред­став­ляет собой кеширу­ющий «обратный» (reverse) прок­си‑сер­вер и аксе­лера­тор HTTP. Прин­цип его работы в общем стан­дартен для такого клас­са прог­рамм. Он получа­ет зап­рос, обра­баты­вает его и сра­зу выда­ет ответ, если он при­сутс­тву­ет в кеше; если нет, то обра­щает­ся к веб‑сер­веру за резуль­татом. Ответ помеща­ется в кеш. Varnish написан с нуля для нор­веж­ской газеты Verdens Gang. Вер­сия 1.0 появи­лась в 2006 году, в 2014-м пред­став­лен релиз 4.0. Основной код дос­тупен под BSD-подоб­ной лицен­зии, но есть и ком­мерчес­кие модули.

Про­ект сра­зу прив­лек себе вни­мание весь­ма гром­кими заяв­лени­ями авто­ра, одно­го из раз­работ­чиков FreeBSD Пола‑Хен­нинга Кам­па (Poul-Henning Kamp) о том, что все (с намеком на Squid) сде­лано неп­равиль­но. И дей­стви­тель­но, Varnish выделя­ет сов­ремен­ный дизайн, эффектив­но исполь­зующий воз­можнос­ти сов­ремен­ных мно­гоп­роцес­сорных сис­тем (Sqiud научил­ся работать с SMP чуть поз­же с вер­сии 3.2). Мно­гопо­точ­ность реали­зова­на с помощью стан­дар­тных потоков POSIX, их количес­тво регули­рует­ся. Это одна из при­чин, почему Varnish не очень хорошо работа­ет в Windows. Каж­дый зап­рос обра­баты­вает­ся в отдель­ном потоке. При­чем с вер­сии 4.0 за получе­ние зап­роса от поль­зовате­ля и переда­чу зап­роса сер­веру отве­чают раз­ные потоки, что еще более повыси­ло про­изво­дитель­ность. Varnish под­держи­вает тех­нологию ESI (Edge Side Includes), поз­воля­ющую раз­бивать веб‑стра­ницу на час­ти и зап­рашивать их отдель­но. Кеш может хра­нить любую информа­цию. В ито­ге Varnish отлично под­ходит для кеширо­вания динами­чес­кого кон­тента.

Для хра­нения дан­ных (кеша, жур­налов опе­раций) исполь­зует­ся вир­туаль­ная память. Управле­нием того, что выг­ружа­ется на диск, занима­ется ОС. Здесь авто­ры Varnish спра­вед­ливо счи­тают, что раз­работ­чики ОС свое дело зна­ют, а дуб­лирова­ние толь­ко ухуд­шает про­изво­дитель­ность.

В отли­чие от Squid, который изна­чаль­но боль­ше ори­енти­ровал­ся на кеширо­вание кли­ент­ских зап­росов, Varnish был раз­работан и опти­мизи­рован имен­но в качес­тве уско­рите­ля HTTP и ничего дру­гого боль­ше не уме­ет. Мы не най­дем здесь под­дер­жку осталь­ных про­токо­лов (FTP, SMTP и про­чие), не уви­дим воз­можнос­ти пря­мого прок­си — кеширо­вания веб‑стра­ниц для эко­номии внеш­него тра­фика (Varnish «при­вязы­вает­ся» к бэкен­дам). Естес­твен­но, отли­чают­ся и воз­можнос­ти по кон­фигури­рова­нию.

Язык кон­фигура­ции Varnish Configuration Language (VCL) — динами­чес­кий, скрипт сам по себе по сути явля­ется отдель­ным пла­гином. Код тран­сли­рует­ся в С (мож­но сра­зу писать встра­иваемый код на С), пос­ле чего инс­трук­ции ком­пилиру­ются в биб­лиоте­ку и под­гру­жают­ся в память. Мож­но вно­сить изме­нения в кон­фигура­цию на лету. Инс­трук­ции в VCL поз­воля­ют кеширо­вать толь­ко опре­делен­ные зап­росы, сни­жая наг­рузку при генера­ции динами­чес­ких объ­ектов, бло­киро­вать дос­туп к опре­делен­ным катало­гам и скрип­там, под­менять заголов­ки и мно­гое дру­гое. Есть и механизм про­вер­ки работос­пособ­ности бэкен­дов (замер вре­мени отве­та, счет­чик неудач­ных про­верок и так далее), воз­можность переза­писи и перенап­равле­ния (rewrite) зап­росов. Вооб­ще, такой под­ход поз­воля­ет про­изво­дить с HTTP-тра­фиком прак­тичес­ки любые манипу­ляции, которые мож­но огра­ничить толь­ко собс­твен­ным вооб­ражени­ем. Под­держи­вает­ся балан­сиров­ка наг­рузки (round robin, random и DNS, Client IP). Воз­можнос­ти рас­ширя­ются при помощи модулей, называ­емых VMOD (Varnish MODules). Про­ект пре­дос­тавля­ет необ­ходимую докумен­тацию, поз­воля­ющую написать такой модуль самос­тоятель­но. Часть мо­дулей уже вклю­чены в стан­дар­тную пос­тавку, некото­рые дос­тупны в виде кон­цепта или находят­ся в раз­работ­ке.

Проект уже предоставляет большое количество модулей
Про­ект уже пре­дос­тавля­ет боль­шое количес­тво модулей

Се­год­ня Varnish исполь­зуют такие веб‑сер­висы, как Facebook, Twitter, Vimeo и Tumblr.

 

Установка и базовая настройка Varnish

Офи­циаль­но рекомен­дует­ся уста­нов­ка Varnish на сов­ремен­ных вер­сиях x64-бит­ных Linux, FreeBSD или Solaris. Пакеты мож­но най­ти в допол­нитель­ных репози­тори­ях (вро­де EPEL или Ubuntu Universe) боль­шинс­тва дис­три­бути­вов Linux и пор­тах *BSD-сис­тем. Сам про­ект пре­дос­тавля­ет репози­тории и под­робные инс­трук­ции для Red Hat, Debian, Ubuntu и FreeBSD. В боль­шинс­тве слу­чаев сле­дует исполь­зовать имен­но репози­торий раз­работ­чика, так как в нем находит­ся более све­жая вер­сия про­дук­та. Воз­можна работа и в Windows (через Cygwin), но опти­миза­ция под *nix-сис­темы не гаран­тиру­ет мак­сималь­ной про­изво­дитель­нос­ти резуль­тата. На сай­те дос­тупны две вер­сии Varnish — 3.x и 4.x, обе явля­ются ста­биль­ными, но под­дер­жка линей­ки 3.x будет прек­ращена в пер­вой полови­не 2015 года. Кста­ти, код дос­таточ­но хорошо написан, поэто­му исправ­лений вно­сит­ся мало (нап­ример, 3-я вет­ка, появив­шаяся в июне 2011-го, содер­жала все­го шесть вер­сий), мож­но не боять­ся исполь­зовать све­жие релизы. Стан­дар­тно Varnish ста­вит­ся перед веб‑сер­вером и кеширу­ет зап­росы. В наг­ружен­ных сис­темах иног­да исполь­зуют более слож­ный вари­ант, ког­да вна­чале зап­рос при­нима­ет лег­кий веб‑сер­вер (nginx, lighttpd), который уме­ет быс­тро отда­вать опре­делен­ные стра­ницы. При необ­ходимос­ти этот сер­вер через Varnish обра­щает­ся к основно­му HTTP-сер­веру, генери­рующе­му кон­тент. Varnish при наличии информа­ции в кеше отда­ет ее отту­да.

Для при­мера уста­новим Varnish в Ubuntu 14.04 LTS в качес­тве фрон­тенда Apache. В дру­гих дис­три­бути­вах отли­чия толь­ко в рас­положе­нии кон­фигура­цион­ных фай­лов и осо­бен­ностях пакет­ных сис­тем.

$ sudo apt-get install apt-transport-https curl
$ sudo curl https://repo.varnish-cache.org/ubuntu/GPG-key.txt | apt-key add -
$ sudo echo "deb https://repo.varnish-cache.org/ubuntu/ trusty varnish-4.0" >> /etc/apt/sources.list.d/varnish-cache.list
$ sudo apt-get update
$ sudo apt-get install varnish

Вот, собс­твен­но, и все. Пос­ле уста­нов­ки Varnish стар­тует и что‑то там кеширу­ет. Зай­мем­ся кон­фигури­рова­нием. Уста­нов­ки парамет­ров запус­ка демона про­изво­дят­ся в фай­ле /etc/default/varnish. Пер­воначаль­но он скон­фигури­рован с некото­рыми парамет­рами. Если открыть файл, то уви­дим внут­ри три готовые нас­трой­ки: minimal, c VCL и advanced.

Файл /etc/default/varnish
Файл /etc/default/varnish

По умол­чанию акти­виро­ван вто­рой режим. При этом сер­вер при­нима­ет под­клю­чения на порт 6081, для адми­нис­три­рова­ния исполь­зует­ся localhost:6082, а бэкенд опре­деля­ется в VCL. Для кеширо­вания выделя­ется 256 Мб памяти. Нас­тро­им так, что­бы Varnish слу­шал 80-й порт, кешируя зап­росы HTTP-сер­вера, рас­положен­ного на этой же машине. Ком­менти­руем нас­трой­ки вто­рого вари­анта и в качес­тве шаб­лона будем исполь­зовать advanced, как более наг­лядный.

$ sudo nano /etc/default/varnish
# Запускать демон varnishd при загрузке системы.
START=yes
# Максимальное количество открытых файлов (для ulimit -n)
NFILES=131072
# Максимальное количество залоченной памяти (for ulimit -l) для блокировки разделяемой памяти лога
# При необходимости следует увеличить размер
MEMLOCK=86000
# По умолчанию экземпляр сервера получает имя текущего узла. При запуске нескольких экземпляров его можно переопределить при помощи -n или
# INSTANCE=$(uname -n)
# По умолчанию слушаются все интерфейсы, но можем указать IP
# VARNISH_LISTEN_ADDRESS=
# Порт, на котором принимаются подключения
VARNISH_LISTEN_PORT=80
# Админ-интерфейс IP и порт
VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1
VARNISH_ADMIN_LISTEN_PORT=6082
# VCL-файл
VARNISH_VCL_CONF=/etc/varnish/default.vcl
DAEMON_OPTS="\
-a ${VARNISH_LISTEN_ADDRESS}:${VARNISH_LISTEN_PORT} \
-f ${VARNISH_VCL_CONF} \
-T ${VARNISH_ADMIN_LISTEN_ADDRESS}:$ {VARNISH_ADMIN_LISTEN_PORT} \

Это основные уста­нов­ки. С осталь­ными мож­но поз­накомить­ся в фай­ле или в докумен­тации про­екта. Перес­тра­иваем Apache, что­бы он слу­шал 8080-й порт. В зависи­мос­ти от текущих уста­новок это мож­но сде­лать в раз­ных фай­лах, в общем идея выг­лядит так:

$ sudo nano /etc/apache2/ports.conf
NameVirtualHost *:8080
Listen 8080

Те­перь оста­лось ука­зать Varnish, где находит­ся HTTP-сер­вер. В /etc/default/varnish это мож­но сде­лать при помощи клю­ча -b (-b localhost:8080), но удоб­нее для это­го исполь­зовать VCL-файл, который ука­зан в перемен­ной VARNISH_VCL_CONF (в сыр­цах есть при­мер example.vcl). Откры­ваем и смот­рим, что­бы внут­ри была инс­трук­ция:

$ sudo nano /etc/varnish/default.vcl
backend apache {
.host = "127.0.0.1";
.port = "8080";
}
Настройки в default.vcl
Нас­трой­ки в default.vcl

Ми­нималь­ные уста­нов­ки готовы. Переза­пус­каем Varnish:

$ sudo service varnish start

Про­веря­ем при помощи netstat, слу­шает­ся ли порт и дос­тупен ли веб‑сер­вер.

 

Продвинутые настройки

Это самый прос­той при­мер, и, как видим, зас­тавить Varnish кеширо­вать зап­росы очень лег­ко, но он пока не «раз­бира­ется» и не вме­шива­ется в тра­фик. Поз­накомив­шись с VCL, мож­но рас­ширить базовые воз­можнос­ти. Парамет­ров, которые мож­но нас­тро­ить, очень мно­го и, что­бы их опи­сать, пот­ребу­ется кни­га. VCL — это язык прог­рамми­рова­ния, в котором най­дем все, что положе­но: перемен­ные, фун­кции, ком­мента­рии и про­чее. Вари­антов исполь­зования мно­го, и с ходу их осво­ить не получит­ся. В качес­тве отправ­ной точ­ки мож­но рекомен­довать докумен­тацию про­екта, в час­тнос­ти Varnish Book. Так­же в Сети уже есть дос­таточ­но шаб­лонов под раз­ные ситу­ации, под­готов­ленных самими поль­зовате­лями. Они будут хорошим под­спорь­ем при изу­чении воз­можнос­тей VCL.

Varnish спо­собен работать с нес­коль­кими HTTP-сер­верами (бэкен­дами). Каж­дый опре­деля­ется ана­логич­но при­меру выше:

backend server1 {
.host = "10.0.0.11";
}
backend server2 {
.host = "10.0.0.12";
}

Пос­ле чего мож­но стро­ить пра­вила, ука­зывая сер­веры по име­ни. Если бэкен­ды рав­нознач­ны и исполь­зуют­ся толь­ко для рас­пре­деле­ния наг­рузки, то дос­таточ­но сооб­щить об этом Varnish с помощью дирек­тивы director:

director balanced_servers round-robin {
{
.backend = server1;
}
{
.backend = server2;
}
}

Мож­но так­же исполь­зовать слу­чай­ный выбор — для это­го вмес­то round-robin про­писы­ваем random. Воз­можна реали­зация и более слож­ных алго­рит­мов. Но для это­го нуж­но поз­накомить­ся с воз­можнос­тями VCL-фай­лов. В default.vcl мы уви­дим нес­коль­ко име­нован­ных бло­ков (фун­кций). По умол­чанию парамет­ры внут­ри отсутс­тву­ют, вот имен­но с их помощью и про­изво­дит­ся тон­кая нас­трой­ка кеширо­вания. Кое‑что мож­но уста­новить, не вни­кая в работу при­ложе­ний на веб‑сер­вере, в более слож­ных слу­чаях пот­ребу­ется глу­бокий ана­лиз выдава­емых стра­ниц (про­ект пре­дос­тавля­ет нес­коль­ко ути­лит, о которых даль­ше).

Раз­берем некото­рые из них. Порядок вызова фун­кций наг­лядно показан в раз­деле VCL Basics, отдель­ные воп­росы кон­фигури­рова­ния есть в до­кумен­тации. Спис­ки ACL поз­воля­ют управлять дос­тупом к опре­делен­ным URL или вруч­ную рас­пре­делять или обра­баты­вать зап­росы некото­рых кли­ентов. Соз­дадим пра­вило, которое вклю­чает все локаль­ные узлы.

acl local {
"localhost";
"192.168.1.0"/24;
! "192.168.1.10";
}

Как видим, раз­реша­ется инверти­рова­ние при помощи !, то есть 192.168.1.10 не попада­ет под пра­вило. Теперь к это­му спис­ку можем обра­тить­ся при помощи конс­трук­ции (client.ip ~ local).

Фун­кция vcl_recv вызыва­ется при получе­нии зап­роса и перед про­вер­кой дан­ных в кеше. Имен­но здесь мож­но модифи­циро­вать зап­рос, уда­лить cookie, про­извести нор­мализа­цию, выб­рать бэкенд в зависи­мос­ти от зап­роса. По умол­чанию Varnish не кеширу­ет зап­росы с уста­нов­ленны­ми cookie. Для ста­тичес­ких стра­ниц луч­ше акти­виро­вать такую воз­можность, для это­го прос­то выреза­ем cookie. Так­же для при­мера зап­ретим дос­туп к фай­лам cron.php и install.php для всех узлов, кро­ме локаль­ных, и ска­жем Varnish, что­бы он перенап­равлял все зап­росы к update.php сра­зу на бэкенд.

sub vcl_recv {
set req.backend = apache
if (req.url ~ "\.(css|js|png|gif|jp(e)?g)")
{
unset req.http.cookie;
}
return (lookup);
if (req.url ~ "^/(cron|install)\.php$" && !client.ip ~ local)
{
error 404 "Page not found.";
}
if (req.url ~ "^/update\.php$"
return (pass);
}
}

Это, конеч­но, не все, что мож­но сде­лать. Исполь­зуя req.http.User-Agent, можем рас­пре­делять бэкен­ды в зависи­мос­ти от бра­узе­ра/устрой­ства кли­ента. Под­робнее. Фун­кция return в слу­чае с vcl_recv может при­нимать аргу­мен­ты: lookup — ука­зыва­ет на необ­ходимость поис­ка в кеше, pass — сра­зу отправ­ляет зап­рос на бэкенд. Пос­леднее, как видим, поз­воля­ет избе­жать кеширо­вания опре­делен­ных типов фай­лов, нап­ример медиа или пос­тоян­но обновля­юще­гося кон­тента.

Не­кото­рые фун­кции вызыва­ют пус­тыми, прос­то что­бы про­пус­тить опре­делен­ную про­вер­ку, ука­зав нуж­ный код воз­вра­та. Кро­ме ука­зан­ных выше, воз­можны вари­анты: deliver, fetch, hash, pipe, error, restart, retry. Фун­кция vcl_hash поз­воля­ет опре­делить уни­каль­ность зап­роса, который будет кеширо­вать­ся. По умол­чанию хеш фор­миру­ется на осно­вании URL и IP/име­ни сер­вера. В боль­шинс­тве слу­чаев это­го дос­таточ­но, но в некото­рых ситу­ациях это­го не хва­тает и, воз­можно, пот­ребу­ется изме­нение пра­вил. Нап­ример, для опре­деле­ния уни­каль­нос­ти исполь­зуют Сookie.

Фун­кция vcl_error поз­воля­ет генери­ровать кон­тент, не обра­щаясь к веб‑сер­веру. Исполь­зует­ся для выдачи сооб­щений об ошиб­ках и редирек­та. Далее в зависи­мос­ти от ситу­ации зап­рос обра­баты­вает­ся vcl_fetch, vcl_pass и vcl_miss. В 4.0 они замене­ны на более удоб­ные фун­кции vcl_backend_fetch и vcl_backend_response, которые вызыва­ются перед переда­чей зап­роса сер­веру и пос­ле получе­ния отве­та соот­ветс­твен­но.

В сле­дующем при­мере мы уби­раем выс­тавле­ние cookie для фай­лов изоб­ражений, а так­же зада­ем вре­мя жиз­ни кеширо­ван­ного содер­жимого для этих фай­лов в один час.

sub vcl_backend_response {
if (bereq.url ~ "\.(png|gif|jpg)$") {
unset beresp.http.set-cookie;
set beresp.ttl = 1h;
}
}

И перед отправ­кой получен­ных от бэкен­да дан­ных вызыва­ется фун­кция vcl_deliver. В прос­тей­шем слу­чае она пус­тует, то есть ответ переда­ется без изме­нений. Но здесь мож­но при желании модифи­циро­вать заголов­ки. Для при­мера прос­то уда­лим все упо­мина­ния о Varnish:

sub vcl_deliver {
remove resp.http.X-Varnish;
remove resp.http.X-Powered-By;
}

Это, конеч­но, далеко не все воз­можнос­ти, но нуж­но идти даль­ше.

 

Управление Varnish

Ра­ботой Varnish мож­но управлять и отсле­живать резуль­тат. Для это­го в пос­тавке идет нес­коль­ко ути­лит, начина­ющих­ся с varnish*. Все они опи­саны в раз­деле «Appendix A: Varnish Programs» Varnish Book. Основной ути­литой явля­ется varnishadm. Имен­но с ее помощью про­изво­дит­ся адми­нис­три­рова­ние, прос­мотр ста­туса и оши­бок, заг­рузка модулей на лету. Прин­цип работы очень прост. Вызыва­ем:

$ sudo varnishadm

Пос­ле чего появит­ся приг­лашение Varnish CLI. Что­бы получить спи­сок команд, сле­дует ввес­ти help.

Список команд varnishadm
Спи­сок команд varnishadm

Ко­манд нем­ного (23), зна­чение боль­шинс­тва понят­но из наз­вания. Под­робнос­ти по каж­дой мож­но получить, вве­дя «help коман­да». Нап­ример, груп­па команд vcl.* поз­воля­ет прос­матри­вать модули и управлять их заг­рузкой‑выг­рузкой. Смот­рим спи­сок модулей:

varnish> vcl.list

Ко­ман­ды param.show и param.set поз­воля­ют прос­матри­вать и изме­нять парамет­ры сер­виса, panic.show и panic.clear — отоб­ражать и очи­щать ошиб­ки, ban и ban.list — ука­зывать стра­ницы, не под­лежащие кеширо­ванию. Две коман­ды varnishtop и varnishhist очень помога­ют при пер­воначаль­ной нас­трой­ке, так как поз­воля­ют прос­мотреть спи­сок наибо­лее час­то встре­чающих­ся парамет­ров (URL, иден­тифика­торы, ста­тус и так далее). Пер­вая ути­лита выводит их в виде top, вто­рая как гис­тограм­му. При зап­росе мож­но исполь­зовать регуляр­ные выраже­ния, поэто­му потерять­ся в боль­шом количес­тве стра­ниц невоз­можно. Нап­ример, прос­мотрим спи­сок наибо­лее зап­рашива­емых URL и заголов­ки:

$ varnishtop -i RxUrl
$ varnishtop -i RxHeader

Еще три очень полез­ные ути­литы, поз­воля­ющие прос­мотреть ста­тис­тику (varnishstat) и информа­цию в жур­налах (varnishlog и varnishncsa). Скрипт varnishtest дает воз­можность про­верить работу кеша Varnish. Для тех, кто не хочет раз­бирать­ся с коман­дной стро­кой, раз­работ­чики пред­лага­ют веб‑интерфейс Varnish Administration Console — очень удоб­ный инс­тру­мент, пред­лага­ющий про­извести все опи­сан­ные опе­рации и получать ста­тис­тику в наг­лядном виде.

Интерфейс Varnish Administration Console
Ин­терфейс Varnish Administration Console

Прав­да, есть минус — дос­тупен он толь­ко в ком­мерчес­кой вер­сии Varnish Plus. Бес­плат­ное ПО пока небога­то вари­анта­ми. Пла­гины, под­держи­вающие Varnish, есть в сис­темах монито­рин­га Collectd, Nagios, Cacti и дру­гих. Спи­сок извес­тных про­ектов мож­но най­ти на сай­те.

График загрузки Varnish в Collectd
Гра­фик заг­рузки Varnish в Collectd
 

Вывод

Varnish — это очень гиб­кая прог­рамма, поз­воля­ющая управлять кеширо­вани­ем тра­фика с веб‑ресур­сов. Боль­шие воз­можнос­ти под­разуме­вают боль­шое количес­тво нас­тро­ек. Поэто­му некото­рое вре­мя при­дет­ся зат­ратить на их изу­чение и под­гонку под кон­крет­ные усло­вия. Но резуль­тат того сто­ит.

Оставить мнение