Как аннулировать объект в кеше Varnish, если он имеет нулевую длину?

Я пытаюсь обойти внутренний сервер, который время от времени начинает обслуживать пустые страницы с ответом 200 OK, заставляя Varnish продолжать обслуживать старые кешированные версии этих страниц (также известный как льготный режим).

Сначала я попытался проверить ответ в vcl_fetch, но, насколько мне удалось выяснить, невозможно определить длину содержимого в vcl_fetch. Затем я попытался выполнить работу в vcl_deliver (где доступен заголовок Content-Length). Это работает, но я не могу понять, как удалить плохой кешированный объект (тот, что с пустой страницей), так что, похоже, это невозможно.

Мне посоветовали установить obj.grace и obj.ttl в vcl_deliver, и это мой текущий код:

sub vcl_deliver {
  # If the front page is blank, invalidate this cached object, in hope
  # that we'll get a new one.
  if (req.url == "/" && std.integer(resp.http.content-length, 0) < 1000) {
    set obj.grace = 0m;
    set obj.ttl = 0m;

    return(restart);
  }
}

Однако Varnish это не нравится и выдает эту ошибку, когда я пытаюсь загрузить VCL:

Message from VCC-compiler:
'obj.grace': cannot be set in method 'vcl_deliver'.
At: ('input' Line 146 Pos 9)
    set obj.grace = 0m;
--------#########------

Я получаю ту же ошибку для obj.ttl, если я удаляю строку obj.grace — кажется, что ни одна из них не доступна для записи в vcl_deliver, хотя документация говорит об обратном. Это на Varnish 3.0.2.


person mikl    schedule 06.03.2012    source источник


Ответы (2)


Что я сделал, так это проверил Content-Length для 0 и 20 в sub_vcl_fech и перезапустил, когда это произойдет.

if (beresp.http.Content-Length == "0" || beresp.http.Content-Length == "20"){
    return(restart);
}

длина содержимого 20 — это то, что мой сервер вернул при возникновении ошибки.

в саб vcl_recv я добавил проверку на количество перезапусков максимум 2

if(req.restarts == 2){
   error 500 req.http.host;
}

Вариант 2

еще один вариант, который я получил из документации по лаку. https://www.varnish-cache.org/docs/3.0/tutorial/handling_misbehaving_servers.html

  1. Выдать ошибку в vcl_fetch, например: ошибка 751 req.http.host;
  2. добавить магический маркер в файл vcl_error.
  3. добавить возврат (перезапуск); в vcl_error
  4. проверить набор магических маркеров в vcl_recv или vcl_fetch
person Brian van Rooijen    schedule 04.08.2014

Делать это в vcl_deliver слишком поздно. Эта подпрограмма вызывается прямо перед отправкой контента клиенту, и obj больше не должен быть доступен (только «resp», который не содержит никаких параметров ttl или Grace).

Вы пытались сделать это в vcl_fetch? Вам не нужно будет вызывать «restart», а напрямую «hit_for_pass».

В любом случае (не уверен в этом) я не думаю, что льготный режим можно использовать в зависимости от содержимого ответа, поскольку он должен запускаться, когда вы не можете получить какое-либо обновление содержимого (сбой серверной части). Возможно, это могло бы сработать, изменив бэкенд на «зомби» и перезапустив запрос, но наверняка, как только вы окажетесь в vcl_fetch, ответ ... будет получен, и льготный режим не сработает.

person Gauthier Delacroix    schedule 02.04.2012
comment
Проблема в том, что я не могу найти способ выяснить, получили ли мы пустой ответ в vcl_fetch. - person mikl; 07.04.2012
comment
Ты сможешь. Просто отметьте beresp.http.content-length вместо resp, чтобы проверять контент, полученный от серверной части, а не контент, который будет отправлен клиенту. - person Gauthier Delacroix; 19.04.2012
comment
Я думаю, вы предлагаете что-то вроде: if(!beresp.http.content-length) { set obj.grace = 5m; } но это все еще не работает для меня. - person Mike Gifford; 06.04.2013
comment
if(!beresp.http.content-length) проверяет наличие заголовка, а не его значение. Лучше использовать if(beresp.http.content-length != "0") (вы не можете использовать > 0, так как заголовок предоставляется в виде строки). - person Gauthier Delacroix; 08.04.2013