Назад | Перейти на главную страницу

Принудительный запрос пропустить кеш, но все же сохранить ответ

У меня есть медленное веб-приложение, перед которым я поставил Varnish. Все страницы статичны (они не меняются для разных пользователей), но их необходимо обновлять каждые 5 минут, чтобы они содержали последние данные.

У меня есть простой скрипт (wget --mirror), который сканирует весь веб-сайт каждые 15 минут. Каждое сканирование занимает около 5 минут. Целью сканирования является обновление каждой страницы в кэше Varnish, чтобы пользователю никогда не приходилось ждать, пока страница сгенерируется (поскольку все страницы были созданы недавно благодаря пауку).

Хронология выглядит так:

Запрос, поступающий между 0:00:00 и 0:05:00, может попасть на страницу, которая еще не была обновлена, и будет вынужден ждать несколько секунд ответа. Это неприемлемо.

Что я бы хотел сделать, так это, возможно, используя некоторую магию VCL, всегда направлять запросы от паука к бэкэнду, но при этом сохранять ответ в кеше. Таким образом, пользователь будет никогда необходимо дождаться генерации страницы, поскольку нет 5-минутного окна, в котором части кеша пусты (кроме, возможно, запуска сервера).

Как я могу это сделать?

req.hash_always_miss должен сделать свое дело.

Не выполняйте полную очистку кеша в начале работы паука. Вместо этого просто заставьте паука работать - и в вашем vcl_recv, установите запросы паука, чтобы всегда пропускать поиск в кеше; они получат новую копию с серверной части.

acl spider {
  "127.0.0.1";
  /* or whereever the spider comes from */
}

sub vcl_recv {
  if (client.ip ~ spider) {
    set req.hash_always_miss = true;
  }
  /* ... and continue as normal with the rest of the config */
}

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

Ответ Шейна выше лучше, чем этот. Это альтернативное решение, более сложное и имеющее дополнительные проблемы. Пожалуйста, проголосуйте за ответ Шейна, а не за этот. Я просто показываю еще один способ решения проблемы.


Моя первоначальная мысль заключалась в том, чтобы return (pass); в vcl_recv а затем, после получения запроса, в vcl_fetch, как-нибудь проинструктируйте Varnish, чтобы он должен кешировать объект, даже если он был специально передан ранее.

Оказывается это невозможно:

Если вы решили передать запрос в более раннюю функцию VCL (например, vcl_recv), вы все равно будете выполнять логику vcl_fetch, но объект не войдет в кеш, даже если вы укажете время кеширования.

Итак, следующий лучший вариант - запустить поиск, как обычный запрос, но убедитесь, что он всегда терпит неудачу. Невозможно повлиять на процесс поиска, поэтому он всегда будет попадать (при условии, что является кешируется; если нет, то все равно пропадет и сохранится). Но мы можем повлиять vcl_hit:

sub vcl_hit {
    # is this our spider?
    if (req.http.user-agent ~ "Wget" && client.ip ~ spider) {
        # it's the spider, so purge the existing object
        set obj.ttl = 0s;
        return (restart);
    }

    return (deliver);
}

Мы не можем заставить его не использовать кеш, но мы можем очистить этот объект из кеша и перезапустить весь процесс. Теперь все возвращается к началу, в vcl_recv, где в конечном итоге выполняется еще один поиск. Поскольку мы очистили объект, который уже пытаемся обновить, он пропустит, затем получит данные и обновит кеш.

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