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

Разрешить varnish отправлять старые данные из кеша, пока загружает новые?

Я кэширую динамически сгенерированные страницы (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 запрос с некоторым регулярным выражением для запрета определенных страниц.

Подводя итог, есть два случая, когда у меня были незадачливые пользователи:

  1. нормальный лак TTL страницы истекает
  2. бэкэнд-пользователи изменяют контент, это отправляет запрос на очистку для лака

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

Тем не менее, для второго случая я создал решение (да, я понимаю, что этот вопрос начался с поиска ответа для первого случая ... плохо сформулированный вопрос с моей стороны):

Вместо отправки запроса на очистку я использовал предложение Шейнса и настроил 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

  • req.grace - определяет, как долго объект может быть просрочен, чтобы Varnish все еще считал его для режима отсрочки.
  • Бересп. благодать - определяет, как долго после того, как beresp.ttl-time Varnish будет хранить объект.
  • req.grace - часто изменяется в vcl_recv в зависимости от состояния бэкэнда.

В настоящее время я использую такую ​​конфигурацию, как написано в руководстве, и она работает нормально ... Вот фрагмент моего файла 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