У меня есть медленное веб-приложение, перед которым я поставил 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
, где в конечном итоге выполняется еще один поиск. Поскольку мы очистили объект, который уже пытаемся обновить, он пропустит, затем получит данные и обновит кеш.
Немного сложно, но работает. Единственное окно для пользователя, застрявшего между очисткой и сохранением ответа, - это время для обработки одного запроса. Не идеально, но неплохо.