Я кэширую динамически сгенерированные страницы (PHP-FPM, NGINX), и перед ними есть лак, это работает очень хорошо.
Однако по истечении тайм-аута кеша я вижу следующее:
Что бы я хотел сделать:
В моем случае это не сайт, на котором устаревшая информация является такой большой проблемой, особенно когда мы говорим о тайм-ауте кеша от нескольких минут.
Однако я не хочу наказывать пользователя за ожидание в очереди и скорее доставить что-то немедленно. Возможно ли это каким-то образом?
Чтобы проиллюстрировать это, вот пример результатов выполнения 5-минутной осады моего сервера, который был настроен на кеширование на одну минуту:
HTTP/1.1,200, 1.97, 12710,/,1,2013-06-24 00:21:06
...
HTTP/1.1,200, 1.88, 12710,/,1,2013-06-24 00:21:20
...
HTTP/1.1,200, 1.93, 12710,/,1,2013-06-24 00:22:08
...
HTTP/1.1,200, 1.89, 12710,/,1,2013-06-24 00:22:22
...
HTTP/1.1,200, 1.94, 12710,/,1,2013-06-24 00:23:10
...
HTTP/1.1,200, 1.91, 12709,/,1,2013-06-24 00:23:23
...
HTTP/1.1,200, 1.93, 12710,/,1,2013-06-24 00:24:12
...
Я не учел сотни запросов в 0.02
или так. Но меня по-прежнему беспокоит, что некоторым пользователям придется ждать почти 2 секунды, пока не появится исходный HTML.
Разве мы не можем здесь лучше?
(Я наткнулся на Отправить лак при кешировании , это звучало похоже, но не совсем то, что я пытаюсь сделать.)
Решение
Ответ Шейна Мэддена содержал решение, но я не сразу понял его. Была еще одна деталь, которую я не включил в свой вопрос, потому что думал, что она не имеет отношения к делу, но на самом деле это так.
Решение CMS, которое я сейчас использую, имеет прослушиватель базы данных varnish и, таким образом, имеет возможность уведомлять varnish о запрете страниц, содержимое которых изменилось. Он отправил PURGE
запрос с некоторым регулярным выражением для запрета определенных страниц.
Подводя итог, есть два случая, когда у меня были незадачливые пользователи:
В обоих случаях у меня есть "незадачливые" пользователи. Во втором случае это облегчается тем, что бэкэнд-пользователи обычно проверяют страницу после того, как она была изменена; но не обязательно.
Тем не менее, для второго случая я создал решение (да, я понимаю, что этот вопрос начался с поиска ответа для первого случая ... плохо сформулированный вопрос с моей стороны):
Вместо отправки запроса на очистку я использовал предложение Шейнса и настроил VCL так, чтобы мой слушатель базы данных varnish мог отправлять специальный запрос для выборки страницы с hash_always_miss
установлен в true
.
В текущей архитектуре я не могу позволить себе роскошь выполнять настоящий асинхронный запрос, но с помощью Как мне сделать асинхронный запрос GET в PHP? Мне удалось создать запрос GET для varnish, который не ждет загрузки страницы, но достаточно хорош, чтобы запустить varnish для выборки страницы из серверной части и ее кеширования.
В результате слушатель базы данных отправил запрос на varnish, и пока я опрашивал конкретную страницу, он никогда не делал мои запросы «неудачными», но как только varnish полностью извлекал страницу из бэкэнда (это может варьироваться от 300 мс до 2 с), он внезапно был там.
Мне еще нужно найти решение, как избежать тех же проблем, когда нормальный TTL заканчивается, но я думаю, что решение также в точности такое, как предлагает Шейн: использование wget для запуска hash_always_miss
, Мне просто нужно быть достаточно умным, чтобы получить список страниц, которые нужно обновить.
Просто кратко, чтобы вы знали, что эта функция, похоже, только что была реализована в последней версии в основной ветке, есть вероятность, что ваша версия может не поддерживать true устаревший во время повторной валидации тем не менее / пример, который я опубликовал, будет обслуживать 9999/10000 запросов с одним бедным баггером, который все еще должен ждать завершения запроса на бэкэнде (все же лучше, чем ничего;) ...
Я не уверен на 100%, почему в предыдущих комментариях говорится, что это не работает, но согласно: https://www.varnish-software.com/static/book/Saving_a_request.html
В настоящее время я использую такую конфигурацию, как написано в руководстве, и она работает нормально ... Вот фрагмент моего файла vcl ...
sub vcl_recv {
# Cache rules above here...
if (req.backend.healthy) {
set req.grace = 30d;
} else {
set req.grace = 300d;
}
}
sub vcl_fetch {
# Fetch rules above here ...
# If backend returns 500 error then boost the cache grace period...
if (beresp.status == 500) {
set beresp.grace = 10h;
return (restart);
}
# How long carnish should keep the objects in cache..
set beresp.grace = 1h;
# Actual TTL of cache - If an object is older than this an update will be triggered to the backend server :)
set beresp.ttl = 1m;
}
Обратите внимание, что если вы хотите предоставить более длительный период отсрочки ответа серверной части (для ошибки 500, как в моей конфигурации), вам нужно будет настроить проверку серверной части ... Вот копия моего внутреннего исследования ..
backend default {
.host = "127.0.0.1";
.port = "8080";
.probe = {
.url = "/nginx-status";
.timeout = 500 ms;
.interval = 3s;
.window = 10;
.threshold = 4;
}
}
Решение, которое я использовал для решения этой проблемы, состоит в том, чтобы убедиться, что TTL на странице никогда не имеет шанса истечь до того, как он обновится - заставляя HTTP-клиент, работающий в одной из моих систем, получать медленную нагрузку вместо неудачливого клиента. запрос.
В моем случае это включает wget
в cron, отправив специальный заголовок для отметки запросов и настройки req.hash_always_miss
на основе этого принудительное извлечение новой копии содержимого в кеш.
acl purge {
"localhost";
}
sub vcl_recv {
/* other config here */
if (req.http.X-Varnish-Nuke == "1" && client.ip ~ purge) {
set req.hash_always_miss = true;
}
/* ... */
}
Для вашего контента это может означать установку Varnish TTL примерно на 5 минут, но с настройкой cron'd wget для выполнения запроса на обновление кеша каждую минуту.
В Varnish 3 это достигается с помощью «Grace Mode». Согласно руководству [1], вам необходимо добавить следующую логику:
sub vcl_fetch {
set beresp.grace = 30m;
} // Makes objects to be cached/stored 30 min beyond its max-age/ttl
sub vcl_recv {
set req.grace = 60s;
} // Allows varnish to serve objects which expired within last minute.
[1] https://www.varnish-cache.org/docs/3.0/tutorial/handling_misbehaving_servers.html#grace-mode