Как использовать Varnish для ускорения моего сайта
Дата обновления перевода 2023-09-19
Как использовать Varnish для ускорения моего сайта
Так как кеш Symfony использует стандартные HTTP кеш заголовки, может быть с лёгкостью заменён любым другим обратным прокси. Varnish - это мощный открытый HTTP-акселератор, способный быстро обслуживать кешированное содержание, включая поддержку Включений крайней стороны.
Заставляем Symfony доверять обратному прокси
Varnish автоматически пересылает IP как X-Forwarded-For
и оставляет загловок
X-Forwarded-Proto
в запросе. Если вы не сконфигурируете Varnish как доверенный
прокси, то Symfony будет видеть все запросы, как исходящие от незащищённых HTTP
соединений хоста Varnish, а не от реального клиента.
Не забудьте вызвать метод Request::setTrustedProxies() в вашем фронт-контроллере, чтобы Varnish выглядел как доверенный прокси и были использованы заголовки X-Forwarded-* .
Маршрутизация и заголовки X-FORWARDED
Чтобы убедиться в том, что маршрутизатор Symfony правильно генерирует URL с
Varnish, должен присутствовать заголовок X-Forwarded-Port
, чтобы Symfony
использовала правильный номер порта.
Этот номер порта соответствует тому, что использует ваша установка для извлечения
внешних связей (80
- значение по умолчанию для HTTP-соединений). Если приложение
также принимает HTTP-соединения, то может быть ещё один прокси (так как Varnish сам
не делает HTTPS) в порту HTTPS по умолчанию 443, который обрабатывает завершение SSL
и переселыает запросы как HTTP-запросы в Varnish с заголовком X-Forwarded-Proto
.
В этом случае, вам нужно добавить следующий отрезок конфигурации:
1 2 3 4 5 6 7
sub vcl_recv {
if (req.http.X-Forwarded-Proto == "https" ) {
set req.http.X-Forwarded-Port = "443";
} else {
set req.http.X-Forwarded-Port = "80";
}
}
Куки и кеширование
По умолчанию, большинство кеширующих прокси, не кешируют ничего, если запрос отправлен с куки или базовым заголовком аутентификации . Это потому, что содержимое страницы должно зависеть от значения cookie или заголовка аутентификации.
Если вы точно знаете, что выходной буфер никогда не использовает сессии или базовую аутентификацию, сделайте так, чтобы Varnish удалил соответствующий загловок из запросов, чтобы предотвратить клиентов от обхода кеширования. На практике, вам понадобятся сессии как минимум для некоторых частей сайта, например, при использовании форм с CSRF-защитой. В этой ситуации, убедитесь, что вы начинаете сессию только тогда, когда это действительно нужно и очищаете сессию, когда она уже не нужна. Как вариант, вы можете рассмотреть Кеширование страниц, содержащих CSRF-защищённые формы.
Cookie, созданные в JavaScript и использованные только в входном буфере (фронт-енде),
например, при использовании Google Analytics, тем не менее отправляются серверу. Эти
cookie неважны для выходного буфера и не должны влиять на решение кешироваия. Сконфигурируйте
ваш кеш Varnish, чтобы он очищал заголовок cookie. Вам стоит оставить cookie сессии,
если он есть, и избавиться от всех остальных, чтобы страницы кешировались, если активной
сессии нет. Если вы изменяли конфигурацию PHP по умолчанию, то ваш cookie сессии имеет имя
PHPSESSID
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
sub vcl_recv {
// Удалить все куки, кроме ID сессии.
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, ";(PHPSESSID)=", "; \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;
}
}
}
Tip
Если содержимое не отличается для каждого пользователя, но зависит от ролей пользователя, то решением будет разделять кеширование по группам. Эта схема реализуется и объясняется FOSHttpCacheBundle под названием Контекст пользователя.
Гарантия последовательного поведения кеширования
Varnish использует заголовки кеша, отправленные вашим приложением,
чтобы определить, как кешировать содержимое. Однако, версии Varnish до 4
не уважали Cache-Control: no-cache
, no-store
и private
. Чтобы
гарантировать последовательное поведение, используйте следуюзую конфигурацию,
если вы всё ещё используете Varnish 3:
1 2 3 4 5 6 7 8 9 10
sub vcl_fetch {
/* По умолчанию, Varnish3 игнорирует Cache-Control: no-cache и private
// https://www.varnish-cache.org/docs/3.0/tutorial/increasing_your_hitrate.html#cache-control
if (beresp.http.Cache-Control ~ "private" ||
beresp.http.Cache-Control ~ "no-cache" ||
beresp.http.Cache-Control ~ "no-store"
) {
return (hit_for_pass);
}
}
Tip
Вы можете увидеть поведение Varnish по умолчанию в форме VCL-файла: default.vcl для Varnish 3, builtin.vcl для Varnish 4.
Активация включений крайней стороны (Edge Side Includes (ESI))
Как объясняется в статье об ESI, Symfony определяет,
общается она с обратным прокси, понимающим ESI, или нет. Когда вы используете
обратный прокси Symfony, вам не нужно ничего делать. Но чтобы заставить Varnish
разрешать ESI-теги вместо Symfony, вам нужна некоторая конфигурация в Varnish.
Symfony использует заголовок Surrogate-Capability
из Edge Architecture,
описанный Akamai.
Note
Varnish поддерживает только атрибут src
для ESI-тегов (атрибуты onerror
и alt
игнорируются).
Для начала, сконфигурируйте Varnish так, чтобы он афишировал свою поддержку
ESI путём добавления заголовка Surrogate-Capability
в запросы, пересылаемые
приложению выходного буфера:
1 2 3 4
sub vcl_recv {
// Добавить заголовок Surrogate-Capability, чтобы афишировать поддержку ESI.
set req.http.Surrogate-Capability = "abc=ESI/1.0";
}
Note
Часть заголовка abc
неважна, кроме случаев, если у вас множество
"сурогатов", которые должны афишировать свои возможности. Смотрите
Заголовок Surrogate-Capability, чтобы узнать детали.
Далее, оптимизируйте Varnish так, чтобы он анализировал содержимое
ответа только тогда, когда в нём есть хотя бы один ESI-тег, проверяя
заголовок Surrogate-Control
, который Symfony добавляет автоматически:
1 2 3 4 5 6 7
sub vcl_backend_response {
// Проверить подтверждение ESI и удалить заголовок Surrogate-Control
if (beresp.http.Surrogate-Control ~ "ESI/1.0") {
unset beresp.http.Surrogate-Control;
set beresp.do_esi = true;
}
}
Tip
Если вы последовали совету о гарантировании последовательного поведеия кеширования, то эти VCL-функции уже существуют. Просто добавьте код к концу функции, они не будут мешать друг другу.
Инвалидация кеша
Если вы хотите кешировать содержимое, которое часто меняется, и всё равно отправлять пользователям наиболее свежую версию, то вам нужно инвалидировать это содержимое. В то время, как инвалидация кеша позволяет вам извлекать содержимое из вашего прокси до того, как истечёт срок действия, она добавляет сложности вашей установке кеширования.
Tip
FOSHttpCacheBundle открытого доступа избавляет от головной боли с инвалидацией, помогая вам организовать вашу установку кеширования и инвалидации.
Документация FOSHttpCacheBundle разъясняет, как сконфигурировать Varnish и другие обратные прокси для инвалидации кеширования.