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

Дата обновления перевода 2025-02-14

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

"В компьютерной науке есть только две сложные вещи: инвалидация кэша и именование сущностей." -- Фил Карлтон

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

Warning

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

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

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

Tip

Если вы хотите использовать инвалидацию кэша, посмотрите на FOSHttpCacheBundle. Этот пакет предоставляет сервисы, чтобы помочь вам с разнличными концептами инвалидации кэша, а также документирует конфигурацию для некольких распространённых кэширующих прокси.

Если одно содержимое соответствует одному URL, то хорошо работает модель PURGE. Вы отправляете запрос к кэшу прокси с HTTP-методом PURGE (использование слова "PURGE" - это соглашение, технически это может быть любой строкой) вместо GET, и заставляеть прокси-кэш определить это и удалить данные из кэша, вместо того, чтобы обращаться к приложению за ответом.

Вот как вы можете сконфигрировать обратный прокси Symfony для поддержки HTTP-метода PURGE. Сначала создайте кэширующее ядро, которое переопределяет метод invalidate():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// src/CacheKernel.php
namespace App;

use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
// ...

class CacheKernel extends HttpCache
{
    protected function invalidate(Request $request, bool $catch = false): Response
    {
        if ('PURGE' !== $request->getMethod()) {
            return parent::invalidate($request, $catch);
        }

        if ('127.0.0.1' !== $request->getClientIp()) {
            return new Response(
                'Invalid HTTP method',
                Response::HTTP_BAD_REQUEST
            );
        }

        $response = new Response();
        if ($this->getStore()->purge($request->getUri())) {
            $response->setStatusCode(Response::HTTP_OK, 'Purged');
        } else {
            $response->setStatusCode(Response::HTTP_NOT_FOUND, 'Not found');
        }

        return $response;
    }
}

Затем зарегистрируйте класс как сервис, который декорирует. http_cache:

1
2
3
4
5
6
7
8
9
10
11
12
13
// src/CacheKernel.php
namespace App;

// ...
use Symfony\Component\DependencyInjection\Attribute\AsDecorator;
use Symfony\Component\DependencyInjection\Attribute\Autoconfigure;

#[Autoconfigure(bind: ['$surrogate' => '@?esi'])]
#[AsDecorator(decorates: 'http_cache')]
class CacheKernel extends HttpCache
{
    // ...
}

Danger

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

Очистка заставляет кэш сбросить ресурс во всех его вариантах (в соответствии с заголовком Vary, см. Варьирование ответа для HTTP-кэша). Альтернативой очистке может быть обновление содержимого. Обновление означает, что кэширующий прокси должен удалить весь локальный кэш и получить содержимое снова. Таким образом, новое содержимое уже доступно в кэше. Недостаток обновления заключается в том, что варианты не инвалидируются.

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

  • Запрещение инвалидирует ответы, совпадающие с ргулярными выражениями в URL или других критериях;
  • Тегирование кэша позвляет вам добавлять тег для каждого содержимого, использованного в ответе, чтобы вы могли инвалидировать все URL, имеющие определённое содержимое.