HTTP-кеширование

Дата обновления перевода 2023-01-16

HTTP-кеширование

Природа насыщенных веб-приложений подразумевает, что они динамические. Вне зависимости от того, насколько эффективно ваше приложение, каждый запрос будет содержать больше работы, чем обслуживание статического файла. Обычно это нормально, но когда вам нужно, чтобы ваши запросы были молниеносно быстрыми, вам понадобится HTTP-кешироваие.

Кеширование на плечах титанов

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

Система кеширования Symfony отличается от других, так как она полагается на простоту и мощь HTTP-кеширования, как это определено в спецификации RFC 7234 - Кеширование. Вместо того, чтобы изобретать кеширование заново, Symfony пользуется стандартом, который определяет базовые коммуникации в Web. Как только вы поймёте основополагающие модели HTTP валидации и истечения срока кэша, вы будете готовы к управлению системой кеширования Symfony.

Так как HTTP-кеширование используется не только Symfony, существует множество статей по данной теме. Если вы новичок в HTTP-кешировании, настоятельно рекомендуем вам прочитать статью Райана Томайко Вещи, которые делают кеши . Другим исчерпывающим источником является Учебное пособие по кешу от Марка Ноттингема.

Кеширование при помощи кеширующего шлюза

При HTTP-кешировании, кеш полностью отделён от вашего приложения и располагается между вашим приложением и клиентом, выполняющим запрос.

Работа кеша заключается в приёме запросов от клиента, и их передаче вашему приложению. Кеш также будет получать ответ от вашего приложения и перенаправлять его клиенту. Кеш является «посредником» в клиент-серверных коммуникациях между клиентом и вашим приложением.

По пути, кеш будет сохранять каждый ответ, который полагает "кешируемым" (см. ). Если этот же ресурс будет запрошен ещё раз, кеш отправит сохранённый (кешированный) ответ клиенту, полностью игнорируя ваше приложение.

Этот тип кeширования известен под именем "кeширующего HTTP шлюза". Существует много кeшеров такого типа, например: Varnish, Squid в режиме обратного прокси, а также обратный прокси Symfony.

Tip

Кеширующие шлюзы иногда называются кешами обратного прокси, суррогатными кешами или даже HTTP-акселераторами.

Обратный прокси Symfony

Symfony содержит обратный прокси (также называемый кеширующим шлюзом), написанный на PHP. Это не кеш обратного прокси с неполным функционалом вроде Varnish , однако это отличный способ начать.

Tip

Чтобы узнать детали о настройке Varnish, см. Как использовать Varnish для ускорения моего сайта.

Используйте опцию framework.http_cache, чтобы включить прокси для окружения производства :

  • YAML
  • XML
  • PHP
1
2
3
4
# config/packages/framework.yaml
when@prod:
    framework:
        http_cache: true

Ядро незамедлительно будет вести себя как обратный прокси: кешировать ответы из вашего приложения и возвращать их клиенту.

Прокси имеет разумную конфигурацию по умолчанию, но может быть тонко настроен через набор опций.

Когда в режиме отладки , Symfony автоматически добавляет заголовок X-Symfony-Cache к ответу. Вы можете также использовать опцию конфигурации trace_level и установить её как none, short или full, чтобы добавить эту информацию.

short добавит информацию только для основного запроса. Он написан кратким образом, что делает запись информации в ваших файлах логов сервера лёгкой. Например, в Apache вы можете использовать %{X-Symfony-Cache}o в заявлениях формата LogFormat. Эта информация может быть использована для извлечения общей информации о действенности кеша ваших маршрутов.

Tip

Вы можете изменить имя заголовка, используемо для информации об остлеживании, используя опцию конфигурации trace_header.

Обратный прокси Symfony - это отличный инструмент для использования при разработке вашего веб-сайта, или когда вы развёртываете веб-сайт на общем хосте, где вы не можете установить ничего, кроме PHP-кода. Но, написанный на PHP, он не может быть таким же быстрым, как прокси, написанный на C.

К счастью, так как все обратные прокси по сути одинаковы, вы должны иметь возможность переключиться на что-то более прочное - вроде Varnish - без каких-либо проблем. См. Как использовать Varnish

Делаем ваши ответы HTTP-кешируемыми

Как только вы добавить кеш обратного прокси (например, как обратный прокси Symfony или Varnish), вы готовы кешировать ваши ответы. Чтобы сделать это, вам нужно сообщить вашему кешу, какие ответы являются кешируемыми и на какое время. Это делается путем установки заголовков кеша в ответе.

HTTP определяет четыре заголовка ответакеша, которые вы можете активировать:

  • Cache-Control
  • Expires
  • ETag
  • Last-Modified

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

  1. Кеширование окончания срока действия Используется, чтобы кешировать весь ваш ответ на определенное количество времени (например, 24 часа). Просто, однако девалидация кеша более сложная.
  2. Кешировани валидации Более сложная модель: используется, чтобы кешировать ваш ответ, но позволяет вам динамически инвалидировать его, как только ваш контент изменяется.

Все HTTP-заголовки, о которых вы будете читать, изобретены не Symfony! Они являются частью спецификации HTTP? которая используется сайтами по всей сети. Чтобы погрузиться в HTTP-кеширование, посмотрите документы RFC 7234 - Кеширование и RFC 7232 - Условные запросы.

Вам, как веб разработчику, настоятельно рекомендуется прочитать эту спецификацию. Её простота и сила, даже спустя более, чем десять лет после её написания, бесценны. Не бойтесь внешнего вида спецификации - её содержание много лучше, чем её обложка!

Кеширование окончания срока действия

Самый простой способ кешировать ответ - это кешировать его на определенное количество времени:

  • Attributes
  • PHP
1
2
3
4
5
6
7
8
9
// src/Controller/BlogController.php
use Symfony\Component\HttpKernel\Attribute\Cache;
// ...

#[Cache(public: true, maxage: 3600, mustRevalidate: true)]
public function index(): Response
{
    return $this->render('blog/index.html.twig', []);
}

6.2

Атрибут #[Cache()] был представлен в Symfony 6.2.

Благодаря этому новому коду, ваш HTTP-ответ будет иметь следующий заголовок:

1
Cache-Control: public, s-maxage=3600, must-revalidate

Он сообщает вашему обратному прокси HTTP кешировать этот ответ на 3600 секунд. Если кто-либо запросит этот URL опять раньше, чем через 3600 секунд, ваше приложение вообще не не будеть задействовано. Если вы используете обратный прокси Symfony, посмотрите на заголовок X-Symfony-Cache, для отладки информации о попаданиях и промахах кеша.

Tip

URI запроса используется в качестве ключа кеша (разве что вы варьируете).

Это очень производительно и легко использовать. Однако девалидация кеша не поддерживается. Если ваш контент изменится, вам нужно будет подождать до тех пор, пока срок действия вашего кеша не закончится для того, чтобы страница обновилась.

Tip

На самом деле, вы можете вручную инвалидировать ваш кеш, но это не ялвяется частью спецификации HTTP-кеширования. См. Девалидация HTTP-кеша .

Если вам нужно установить заголовки кеша для многих разных действий контроллера, посмотрите FOSHttpCacheBundle. Он предоставляет способ определять заголовки кеша, основываясь на образец URL и другие свойства запроса.

В конце-концов, для более детальной информации об окончании срока действия кеша, см. Срок действия HTTP-кеша.

Кеширование валидации

С кешированием с окончанием срока действия, вам просто нужно сказать "кешировать на 3600 секунд!". Но, когда кто-то обновляет кешированный контент, вы не сможете увидеть его до тех пор, пока не истечет срок действия кеша.

Если вам нужно увидеть обновленный контент сразу же, вам нужно либо аннулировать ваш кеш или использовать модель кеширования валидации.

Чтобы узнать больше, см. Валидация HTTP-кеша.

Безопасные методы: Кеширование только запросов GET или HEAD

HTTP кеширование работает лишь для "безопасных" HTTP методов (таких как GET и HEAD). Это означает 2 вещи:

  • Не пытайтесь кешировать запросы PUT или DELETE. Это не сработает, и по хорошей причине. Эти методы не должны быть использованы при изменении состояния вашего приложения (например, удалении поста блога). Их кеширование будет предотвращать некоторые запросы от попадания и изменения вашего приложения.
  • Запросы POST обычно считаются некешируемыми, но их можно кешировать, когда они содержат ясную информацию о свежести. Однако, кеширование POST не широко реализуется, поэтому вам стоит его избегать, если это возможно.
  • Вам никогда не стоит изменять состояние вашего приложение (например, обновлять пост блога), во время ответа на запрос GET или HEAD. Если эти запросы будут кешированы, будущие запросы могут никогда не попасть на ваш сервер.

Другие методы ответа

Класс Response содержит также множество других методов, относящихся к кешу. Вот самые полезные из них:

1
2
3
4
5
// помечает ответ как "просроченный"
$response->expire();

// форсирует возврат ответа 304 без контента
$response->setNotModified();

В дополнение к этому, все основные HTTP заголовки, относящиеся к кешу, могут быть установлены при помощи одного метода setCache():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// используйте этот метод, чтобы установить несколько настроек кеша за один вызов
// (этот пример перечисляет все доступные настройки кеша)
$response->setCache([
    'must_revalidate'  => false,
    'no_cache'         => false,
    'no_store'         => false,
    'no_transform'     => false,
    'public'           => true,
    'private'          => false,
    'proxy_revalidate' => false,
    'max_age'          => 600,
    's_maxage'         => 600,
    'immutable'        => true,
    'last_modified'    => new \DateTime(),
    'etag'             => 'abcdef'
]);

Tip

Все эти опции также доступны при использовании атрибута #[Cache()].

Инвалидция кеша

Инвалидация кеша не является частью HTTP-спецификации. Однако, она может быть очень ползеной для удаления различных записей HTTP-кеша, как только какой-либо контект вашего сайта обновляется.

Чтобы узнать больше, см. Аннуляция кеша.

Использование Включений крайней стороны

Когда на странице присутствуют динамические части, вам не удастся кешировать целые страницы, а придется это делать по частям. Читайте Работа с включениями крайней стороны, чтобы узнать, как сконфигурировать разные стратегии кеширования для определенных частей вашей страницы.

HTTP-кеширование и сессии пользователей

Каждый раз, когда сессия начинается во время запроса, Symfony превращает ответ в приватный некешируемый ответ. Это лучшее поведение по умолчанию, чтобы не кешировать приватную инфомацию пользователя (например, корзину покупок, детали профиля пользователя и т.д.) и не отобазить её другим посетителям.

Однако, даже запросы, которые пользуются преимуществами сессии, могут быть кешированы при некоторых обстоятельствах. Например, инфомация, связанная с какой-то группой пользователей, может быть кеширована для всех пользователей, принадлежащих к этой гуппе. Обработка этих продвинутых сценариев кеширования находится за пределами области действия Symfony, но их можно ррешить с помощью FOSHttpCacheBundle.

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

1
2
3
use Symfony\Component\HttpKernel\EventListener\AbstractSessionListener;

$response->headers->set(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER, 'true');

Заключение

Symfony создан таким образом, чтобы следовать проверенным «правилам движения» в HTTP. Кеширование - не исключение. Овладение системой кеширования Symfony, подразумевает близкое знакомство с моделями кэширования HTTP и их эффективное использование. Это означает, что вместо того, чтобы полагаться только на документацию Symfony и примеры кода, вы получаете доступ к целому миру знаний, относящихся к кешированию в HTTP и кеширующим шлюзам, таким как Varnish.